Автозаполнение полей модели Django при создании экземпляра другой модели

У меня есть три модели Student, Question и StudentAndQuestion

class Student(models.Model):
    class Meta:
        verbose_name_plural = "Students"
    name = models.CharField(max_length=150)
    surname = models.CharField(max_length=150)
    code = models.CharField(max_length=10)
#    group = models.ForeignKey(Group,on_delete=models.CASCADE)
    points = models.IntegerField(default=0)


class Question(models.Model):
    class Meta:
        verbose_name_plural = "Questions"

    text = models.CharField(max_length=1500)
    variants = models.CharField(max_length=1500)
    theme = models.OneToOneField(Theme, on_delete=models.CASCADE)
    anwser = models.CharField(max_length=1500)


class StudentAndQuestion(models.Model):
    question = models.OneToOneField(Question,on_delete=models.CASCADE)
    student = models.OneToOneField(Student,on_delete=models.CASCADE)
    is_learned = models.BooleanField(default=0)
    points = models.IntegerField(default=0)

Я хочу, чтобы Django заполнял StudentAndQuestion, когда я создаю новый экземпляр учеников (например, создаю строки для всех вопросов и устанавливаю точки на ноль), и когда я создаю новый экземпляр вопроса, добавляю его всем старым ученикам

уверены ли вы в OneToOneField, это означает, что когда у экземпляра studentAndQuestion есть question, другие экземпляры больше не могут его иметь. ForeignKey - это то, что нужно для работы + Сигнал Django

Lemayzeur 01.05.2018 17:04

@Lemayzeur, я уже заметил это, спасибо!

Danny Belchenko 01.05.2018 17:32

Так он работает сейчас?

Lemayzeur 01.05.2018 17:39

@Lemayzeur ага :)

Danny Belchenko 01.05.2018 17:48
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
1 242
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете прослушать Опубликовать сигнал сохранения, генерируемый при сохранении этих моделей, и выполнить необходимое создание в обработчике. Этот сигнал вызывает обработчик с аргументом created, который является True, если была создана новая запись.

Обратитесь к документация по сигналам, чтобы узнать, как зарегистрировать свои обработчики. Образец выглядит следующим образом

from django.db.models.signals import post_delete, post_save

from .models import Student, Question, StudentAndQuestion


def add_question_to_students(sender, instance, created, *args, **kwargs):    
question = instance
if created:
    StudentAndQuestion.objects.bulk_create([
        StudentAndQuestion(question=question, student_id=student_id)
        for student_id in Student.objects.values_list("id", flat=True)
    ])

def add_student_to_question(sender, instance, created, *args, **kwargs):    
student = instance
if created:
    StudentAndQuestion.objects.bulk_create([
        StudentAndQuestion(question=question_id, student=student)
        for question_id in Question.objects.values_list("id", flat=True)
    ])

post_save.connect(add_question_to_students, sender=Question)
post_save.connect(add_student_to_question, sender=Student)

В качестве альтернативы вы можете переопределить сохранение в обеих моделях, чтобы сделать то же самое.

class Question(models.Model):
    ....
    def save(*args, **kwargs):
        is_create = self.pk is None
        instance = super().save(*args, **kwargs)
        add_question_to_students(Question, self, is_created)

class Student(models.Model):
    ....
    def save(*args, **kwargs):
        is_create = self.pk is None
        instance = super().save(*args, **kwargs)
        add_student_to_question(Student, self, is_created)

Я считаю, что последнее более ясно, так как легче узнать, что все происходит при сохранении, но это может привести к циклическим зависимостям, если модели находятся в разных приложениях.

Я получил сообщение "NOT NULL constraint failed", используя второй метод.

Danny Belchenko 01.05.2018 15:21

Вероятно, это потому, что вы сделали это до супер звонка ... Или, может быть, self и instance не равны, и это должен был быть self = super(), но это кажется странным

Resley Rodrigues 03.05.2018 07:20

Другие вопросы по теме