196

There is this line in the Django tutorial, Writing your first Django app, part 1:

p.choice_set.create(choice='Not much', votes=0)

How is choice_set called into existence and what is it?

I suppose the choice part is the lowercase version of the model Choice used in the tutorial, but what is choice_set? Can you elaborate?

UPDATE: Based on Ben's answer, I located this documentation: Following relationships "backward".

7
  • I should have just linked to that documentation, it is clearer than my answer.
    – Ben James
    Jan 12, 2010 at 13:22
  • 1
    @Ben James: no, I appreciate to have it formulated in a different way, especially the elaboration of what the ORM is doing. The Django documentation can be terse at times. Jan 12, 2010 at 15:06
  • 52
    Thank you for asking this, I was confused by this as they do not explain it in the tutorial.
    – claudio
    Mar 30, 2013 at 5:40
  • 7
    Wow, that's a loaded line of code for a newbie. For me the hurdle was understanding that we're getting a Choice Object, related to the Question, in order to then increment it's choice.votes by one. The RelatedManager concept has not been mentioned in the tutorial to this point so it can be a real stumbling block.
    – frozenjim
    Aug 6, 2015 at 15:40
  • 3
    @HemantKumar I tried to correct the docs but was not approved. If you find the same issue feel free to comment in the PR: github.com/django/django/pull/13330
    – Escachator
    Aug 20, 2020 at 16:57

2 Answers 2

234

You created a foreign key on Choice which relates each one to a Question.

So, each Choice explicitly has a question field, which you declared in the model.

Django's ORM follows the relationship backwards from Question too, automatically generating a field on each instance called foo_set where Foo is the model with a ForeignKey field to that model.

choice_set is a RelatedManager which can create querysets of Choice objects which relate to the Question instance, e.g. q.choice_set.all()

If you don't like the foo_set naming which Django chooses automatically, or if you have more than one foreign key to the same model and need to distinguish them, you can choose your own overriding name using the related_name argument to ForeignKey.

2
  • Thanks. I know much more now. Isn't choice_set a "Manager" ? (that can return an instance of class QuerySet). Or is it the same thing? Jan 12, 2010 at 12:41
  • 3
    You're correct, it's a RelatedManager which can create querysets.
    – Ben James
    Jan 12, 2010 at 13:22
2

Two crucial questions are asked here. First: How is choice_set called into existence. Second: What is it?

For all new developers like me, Let me describe how I made it easy for me. Let me answer the second question first. "What is it", through these 3 words? Model Instance, Objects-set related to that instance, Related_manager.

Models.py from Django tutorial:

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

Instance:

q = Question.objects.get(pk=3)
# Here q is an instance of model class 'Question'.

c = Choice.objects.get(pk=32)
# Here c is an instance of model class 'Choice'.

'Model Instance' is a single 'ROW' of an entire 'TABLE' of your database

Here, the Question Model is used as a foreign key to the Choice Model. Therefore, all the objects-set related to instance q can be filtered by using:

q.choice_set.all()

Therefore, choice_set here is, all the choices related to the question, that has pk=3.

Now, the answer to the first question needs the third word Related Manager. Django documentation here:-

If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased. This Manager returns QuerySets, which can be filtered and manipulated as described in the “Retrieving objects” section above.

This word (choice_set) can be changed using the 'related_name' parameter in the Foreign_key.

question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices")

For backward relationtionship through foreign key:

q.choice_set.all()
# If using related_name, then it is same as 
q.choices.all()

# All the choices related to the instance q.

For forward relationship:

choice_qs = Choice.objects.all()
choice_qs.filter(question=q)
# Same result as above. All the choices related to instance q.

Your Answer

Reminder: Answers generated by Artificial Intelligence tools are not allowed on Stack Overflow. Learn more

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.