Reputation: 43
I have three models Student, Question and 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)
I want Django make fill into StudentAndQuestion when i create new instance of students (for example create rows for all Questions and set points to zero) and when i create new instance of Question add it to all old students
Upvotes: 1
Views: 1884
Reputation: 2288
You can listen to the Post Save Signal emitted when these models are saved, and do the needed creation in the handler. This signal calls the handler with an argument called created
which is True
if a new record was created.
Refer to the documentation on signals to learn how to register your handlers. A sample is as follows
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)
Alternatively, you could override the save in both models to do the same
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)
I feel the later is clearer as it is easier to find out what all is happening on save, but it can lead to circular dependencies if the models are in different apps.
Upvotes: 1