from django.db import models
class Question(models.Model): text = models.CharField(max_length=200) title = models.CharField(max_length=200) total_response_count = models.IntegerField() topic = models.CharField(max_length=20) sequence_num = models.IntegerField() select_multiple = models.BooleanField(default=False)
def __str__(self): return self.text
class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) text = models.CharField(max_length=200) response_count = models.IntegerField() response_percent = models.FloatField()
def __str__(self): return self.text
from censustest.models import Question,Choice
q=Question(text="Q1",title="",topic="",sequence_num=0,total_response_count=0)c=Choice(text="C1",response_count=5,response_percent=0.3,question=q)print("q.id %s, c.question %s, c.question_id %s" % (q.id, c.question, c.question_id)) # None,Q1,NoneQuestion.objects.bulk_create([q])print("After creating q: q.id %s, c.question %s, c.question_id %s" % (q.id, c.question, c.question_id)) # valid id,Q1,NoneChoice.objects.bulk_create([c]) # ERROR: IntegrityError
from censustest.models import Question,Choice
q=Question(text="Q1",title="",topic="",sequence_num=0,total_response_count=0)c=Choice(text="C1",response_count=5,response_percent=0.3)Question.objects.bulk_create([q])c.question=qprint("c.question %s, c.question_id %s" % (c.question, c.question_id)) # Q1,valid idChoice.objects.bulk_create([c]) # works, no error
def save(self, *args, **kwargs):
self.question_id = self.question.id
super(Choice, self).save(*args, **kwargs)
Thanks for the reply Kirby.I understand that the Question's pk is null when you pass in the Question to the Choice constructor. But when you save the Choice, the Question was saved earlier so the Question's pk is not null. But the Choice's question_id attribute (representing the Question's pk) is still null when you save the Choice.1. Should the Choice's question_id have been updated to it's current value when saving the Choice?
I read some more about what happens when you save an object in Django and it seems like the Choice's question_id should be updated when the data is prepared for the db (step 3 from the link).I understand I can override the Choice class's save method to do this (see code below) but it seems like it should be something that is already done by the Django framework.
def save(self, *args, **kwargs):
self.question_id = self.question.id
super(Choice, self).save(*args, **kwargs)
2. Is there a better way to bulk create objects in a one-to-many relationship (Questions and Choices)?My idea (from the code snippet after models.py) was to bulk create the Questions and then bulk create the Choices but this has the problem mentioned above of the Choice's FK (question_id) not being updated even after the Questions were bulk created.
def _resync_fk_fields(self, obj):
for field in type(obj)._meta.local_concrete_fields:
if isinstance(field, models.ForeignKey):
rel_obj = getattr(obj, field.name)
if rel_obj is not None:
setattr(obj, field.get_attname(), rel_obj.id)