What is choice_set in this Django app tutorial? - python

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".

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.

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.

Related

Reverse accessor clasher with Django [duplicate]

D:\zjm_code\basic_project>python manage.py syncdb
Error: One or more models did not validate:
topics.topic: Accessor for field 'content_type' clashes with related field 'Cont
entType.topic_set'. Add a related_name argument to the definition for 'content_t
ype'.
topics.topic: Accessor for field 'creator' clashes with related field 'User.crea
ted_topics'. Add a related_name argument to the definition for 'creator'.
topics.topic: Reverse query name for field 'creator' clashes with related field
'User.created_topics'. Add a related_name argument to the definition for 'creato
r'.
topicsMap.topic: Accessor for field 'content_type' clashes with related field 'C
ontentType.topic_set'. Add a related_name argument to the definition for 'conten
t_type'.
topicsMap.topic: Accessor for field 'creator' clashes with related field 'User.c
reated_topics'. Add a related_name argument to the definition for 'creator'.
topicsMap.topic: Reverse query name for field 'creator' clashes with related fie
ld 'User.created_topics'. Add a related_name argument to the definition for 'cre
ator'.
You have a number of foreign keys which django is unable to generate unique names for.
You can help out by adding "related_name" arguments to the foreignkey field definitions in your models.
Eg:
content_type = ForeignKey(Topic, related_name='topic_content_type')
See here for more.
http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
Example:
class Article(models.Model):
author = models.ForeignKey('accounts.User')
editor = models.ForeignKey('accounts.User')
This will cause the error, because Django tries to automatically create a backwards relation for instances of accounts.User for each foreign key relation to user like user.article_set. This default method is ambiguous. Would user.article_set.all() refer to the user's articles related by the author field, or by the editor field?
Solution:
class Article(models.Model):
author = models.ForeignKey('accounts.User', related_name='author_article_set')
editor = models.ForeignKey('accounts.User', related_name='editor_article_set')
Now, for an instance of user user, there are two different manager methods:
user.author_article_set — user.author_article_set.all() will return a Queryset of all Article objects that have author == user
user.editor_article_set — user.editor_article_set.all() will return a Queryset of all Article objects that have editor == user
Note:
This is an old example — on_delete is now another required argument to models.ForeignKey. Details at What does on_delete do on Django models?
"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."
But if you have more than one foreign key in a model, django is unable to generate unique names for foreign-key manager.
You can help out by adding "related_name" arguments to the foreignkey field definitions in your models.
See here:
https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
If your models are inheriting from the same parent model, you should set a unique related_name in the parent's ForeignKey. For example:
author = models.ForeignKey('accounts.User', related_name='%(app_label)s_%(class)s_related')
It's better explained in th
If your models are inheriting from the same parent model, you should set a unique related_name in the parent's ForeignKey. For example:
author = models.ForeignKey('accounts.User', related_name='%(app_label)s_%(class)s_related')
It's better explained in the docs
I had a similar problem when I was trying to code a solution for a table that would pull names of football teams from the same table.
My table looked like this:
hometeamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE)
awayteamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE)
making the below changes solved my issue:
hometeamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE,related_name='home_team')
awayteamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE,related_name='away_team')
But in my case i am create a separate app for some functionality with same model name and field ( copy/paste ;) ) that's because of this type of error occurs i am just deleted the old model and code will work fine
May be help full for beginners like me :)
This isn't an ultimate answer for the question, however for someone it may solve the problem.
I got the same error in my project after checking out a really old commit (going to detached head state) and then getting the code base back up to date. Solution was to delete all *.pyc files in the project.
Do as the error message instructs you to:
Add a related_name argument to the
definition for 'creator'.

Django: objects and model_set

I am learning django 1.10 official tutorial part 2
class Question(models.Model):
# ......
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
#.......
Recent i saw the following command:-
q = Question.objects.get(id=1)
q.choice_set.all()
My questions:-
How Question instance contain choice_set, i know it for accessing related objects.
Why is this not valid
c = Choice.objects.get(id=1)
c.question_set.all()
The Question model does not have an explicit reference to the Choice model; however, Django automatically adds a reverse-reference, which is by default called choice_set. You can override this by related_name keyword on the model such as:
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='choices')
Now you can reference all of the choices for a question like this:
q = Question.objects.get(pk=1)
q.choices.all()
To answer your second question, the reason you cannot use reference question_set.all() from a choice object is because for each choice, there is only one question plus there is an explicit reference to the question object. In other words the Choice model already has a field called Question, which points to the Question model.
Hope that helps.

Where does <model>_set come from in my Django model?

I am going through the Django tutorial: https://docs.djangoproject.com/en/dev/intro/tutorial01/
And I am looking at the example of using the python shell with manage.py. Code snippet is copied from website:
# Give the Poll a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a poll's choices) which can be accessed via the API.
>>> p = Poll.objects.get(pk=1)
# Display any choices from the related object set -- none so far.
>>> p.choice_set.all()
[]
This example is using a Poll model with a question and choice of answers, defined here:
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField()
Now I don't understand where the object choice_set comes from. For a question we have a group of "Choices". But where is this explicitly defined? I just seems two classes are defined. Does the models.foreignKey(Poll) method connect the two classes (hence tables)?
Now where does the suffix "_set" come from in choice_set. Is it because we are implicitly defining a one-to-many relationship between the Poll and Choice tables, hence we have a "set" of choices?
choice_set is put there automatically by the Django ORM because you have a foreign key from Choice to Poll. This makes it easy to find all the Choices for a particular Poll object.
It is hence not explicitly defined anywhere.
You can set the name of the field with the related_name parameter to ForeignKey.
The relationship _set command - in this instance choice_set- is an API accessor for the relationship (i.e., a ForeignKey, OneToOneField, or ManyToManyField).
You can read more about Django relationships, the relationship API, and _set here
But where is this explicitly defined?
It isn't; this is Django magic.
I just seems two classes are defined. Does the models.foreignKey(Poll) method connect the two classes (hence tables)?
Correct.
Now where does the suffix "_set" come from in choice_set. Is it because we are implicitly defining a one-to-many relationship between the Poll and Choice tables, hence we have a "set" of choices?
Yes. It's just a default; you can set the name explicitly via the normal mechanism.

django model for list of objects' relations to each other?

I have a social-clique-object.
In each social-clique-object I have a list of friend-objects.
Each friend-object has a relationship-object (full of fun facts like when they met) with each other friend.
Herein I am stuck. How do I properly define my models so that I can query any friend-object to pull up their shared relationship-object?
I do not see this is simply solved with a bidirectional model like this answer since I am dealing with a large and growing list of friend objects (in the linked-to solution they create two different models e.g. friend_a and friend_b).
My current approach was for the Relationship object to look like what is posted below. I would have to add logic in my code to prevent duplicate Relationship objects... but this
class Relationship(models.Model):
social_clique = models.ForeignKey( Social_Clique )
friend_0 = models.ManyToManyField( Friend, related_name='friend_0' )
friend_1 = models.ManyToManyField( Friend, related_name='friend_1' )
I sense I am missing the right keyword to google for to find the ORM design pattern for this problem. Any suggestions on the right description of this problem or how to address this?
It doesn't make sense for either of the friend_x fields to be ManyToManys. The relationship between friends is ManyToMany, but Relationship is itself the intermediary model in the many-to-many relationship (hence the name). So the friend_ fields should be ForeignKeys, and then you additionally define a ManyToMany field from Friend to itself using Relationship as the through model:
class Relationship(models.Model):
social_clique = models.ForeignKey(Social_Clique)
friend_0 = models.ForeignKey(Friend, related_name='friend_0')
friend_1 = models.ForeignKey(Friend, related_name='friend_1')
class Friend(models.Model):
... other fields ...
friends = models.ManyToManyField('Friend', through=Relationship)
Now it's easy to go from two friends (me and my_friend) to their shared relationship:
Relationship.objects.get(friend_0=me, friend_1=my_friend)
or
me.friend_0.filter(friend1=my_friend)
etc. And you can still get all my friends:
me.friends.all()

Django model inheritance: Delete subclass keep superclass

When dealing whith model inheritance in django is it possible to remove a instance of model subclass, without removing the superclass itself?
Using the Django example, can you remove just the Resturaunt object and retain the Place object?
Yesterday I was looking for an answer to this question and I came up with this solution, which was enough for my problem but could be scaled up as needed.
Assuming you have a Restaurant and a Place django models, the way to delete a restaurant only without touching the row inside the Place's table is creating a "fake" Restaurant model like this:
class FakeRestaurant(models.Model):
place_ptr = models.PositiveIntegerField(db_column="place_ptr_id", primary_key=True)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
class Meta:
app_label = Restaurant._meta.app_label
db_table = Restaurant._meta.db_table
managed = False
Now, you can retrieve objects from that table as if it had no bound external relationship:
place = Place.objects.get(pk=1)
restaurant = Restaurant.objects.get(pk=1)
fake_restaurant = FakeRestaurant.objects.get(pk=1)
fake_restaurant.delete()
fake_restaurant and restaurant won't exist anymore, place will remain untouched.
Cheers,
Davide
In Django 1.9 parameter keep_parents was added to model delete() function, so to keep parents just call:
restaurant.delete(keep_parents=True)
Docs: https://docs.djangoproject.com/en/1.10/ref/models/instances/#django.db.models.Model.delete
UPDATE:
Apparently, this feature is not working properly in Django 1.9, please see the comments.

Categories