Setting up default ForeignKey in django models - python

I need to set up default Foreign Key for a model at the model declaration stage (in models.py). I use the following code:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __unicode__(self):
return str(self.pub_date)
def create_question():
q=Question(question_text='default text', pub_date=datetime.now())
q.save()
return q.id
class Choice(models.Model):
question = models.ForeignKey(Question, default=lambda: create_question())
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
This works fine, the Choice instance and associated Question instance are created... But saving of Choice instance leads to creation of two additional (useless) Question instances. It seems like that default-lambda is called several times during Choice instance saving. I don't need these additional Question instances. How to avoid their creation?
NOTE: In python-shell everything works well:
c=Choice(votes=5, choice_text='dim')
c.save()
creates one instance of Choice and one associated instance of Question. Only using admin save button leads to extra Question instances creation!

Related

How do we pick objects from a model to create copies in another model adding extra parameters in django?

I have the following models:
class Questionnaire(models.Model):
questionnaire_name = models.CharField(max_length=120, default="")
...
class Question(models.Model):
question_body = models.TextField()
...
class QuestionnaireContent(models.Model):
questionnaire = models.ForeignKey(Questionnaire)
question = models.ForeignKey(Question)
...
The QuestionnaireContent model acts as a list of questionnaire templates. Those are assigned to users eventually, using:
class QuestionnaireAssignment(models.Model):
user = models.ForeignKey(User)
questionnaire = models.ForeignKey(Questionnaire)
Now, ideally, I would like this assignment to generate a new questionnaire 'instance' in another model which would have the following fields:
class QuestionnaireInstance(models.Model):
user = models.ForeignKey(User)
questionnaire = models.ForeignKey(Questionnaire)
question = models.ForeignKey(Question)
visibility = models.BooleanField()
But I would like that QuestionnaireInstance to be created automatically once a QuestionnaireAssignment instance is created. I guess I could rewrite the save function of QuestionnaireAssignmentbut I am wondering if there is a simpler/cleaner way to do this?
The idea is I want from the template questionnaires to create instance for users that can be customized for that user (adding attribute visibility and eventually changing the questions).
Thanks for your help!!
Overriding the save() method of QuetionnaireAssignment is one possibility. Note that you don't have to completely rewrite save() since you can call super().save().
Alternatively, use the postsave signal instead: docs.djangoproject.com/en/4.1/topics/signals

'Questions' object has no attribute 'choice_set'

I've been following the Django documentation "Write your app tutorial" and I keep running into the above error. It seems to be coming from this line
selected_choice = question.choice_set.get(pk=request.POST['choice'])
This is my Questions and Choices object:
class Questions(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date Published')
def __str__(self):
return self.question_text
class Choices(models.Model):
questions = models.ForeignKey(Questions, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
The code is exactly as it is on the official documentation, so I can't tell exactly where the error is coming from
"choice_set" is created as an object in Questions because the Choice model has a foreignKey relationship to Questions, so for every entry in Questions, there might be some Choice instances (rows of data in the Choice table). The general rule is a lowercase version of the model name, followed by "_set".
Your model is called Choices plural (with an 's'), so the set will probably be called "choices_set". I'm pretty sure that's the remaining problem for you.
You need to define the Choice model with a foreign key to Questions, otherwise django won't create choice_set.
Your Class name is Choices, so if you try choices_set things might work

Django: How is <classname>_set attribute created in models.Model subclass?

In Django, I can have a model Question and a model Choice:
class Question(models.Model):
...
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
...
def __str__(self):
return choice_text
I can then do this:
>>>q = Question(question_text = 'How are you?', pub_date = timezone.now())
>>>q.choice_set.all()
<QuerySet []>
The q.choice_set, according to my understanding, accesses the set of Choice objects in our database which refer to q by their foreign key.
My question is: How is the choice_set attribute being created? I've never seen a attribute name taking the name of another class in lower case letters. How is this achieved?
EDIT: To clarify, I'm asking about how Django sets the name of the variable dynamically, not the variable contents.
The name is decided by ForeignObjectRel.get_accessor_name. The actual attribute is set via setattr() in RelatedField.contribute_to_related_class.
Essentially, this happens when you create an instance of ForeignKey:
attribute_name = YourModel._meta.model_name + '_set'
setattr(foreign_key, attribute_name, SomeDescriptorClass(foreign_key))

Counting Boolean Values in field of Child Model in Django QuerySet API

I have the following model (below).
I would like a query that returns every record of parent Question(models.Model), where ALL the values for the is_relevant field within the child Choice(models.Model) are "True".
Having a difficult time creating the QuerySet. Any Assistance would be very helpful.
model.py
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
is_relevant = models.BooleanField()
You can use the reverse relationship of the Question model like so:
Question.objects.filter(choice__is_relevant=True)
The choice in choice__is_relevant is the lowercase name of the model Choice.
Reference: Relationship lookups

Django form for model referenced by foreign keys

I am creating a quiz application in django. As of right now, I have two models, Question and Answer.
class Question(models.Model):
question_text = models.CharField(max_length=255)
video_ref = models.ForeignKey('Video')
class Answer(models.Model):
question_ref = models.ForeignKey('Question')
answer_text = models.CharField(max_length=255)
correct = models.BooleanField()
This setup allows me to have variable numbers of potential answers to every question with a possibility of multiple correct answers.
I want to create a form model for a Question such that every Answer that points to the Question is part of the form. How can this be done?
You can do as follow:
forms.py
class QuestionForm(forms.ModelForm):
answers = forms.ModelMultipleChoiceField(queryset=Question.answer_set.all(), widget=forms.CheckboxSelectMultiple)
class Meta:
model = Question
Using forms.ModelMultipleChoiceField and the widget forms.CheckboxSelectMultiple django will render the form with checkbox for you.

Categories