I am building the example django polls application. I want to exclude all polls, which have no choices. For that I have to access the related choices objects:
return Question.objects.filter(
pub_date__lte=timezone.now()
).exclude(
choice_set__count=0
).order_by('-pub_date')[:5]
But this query results in a field error:
Cannot resolve keyword 'choice_set' into field. Choices are: choice, id, pub_date, question_text
How can I query related models from the query?
To filter against a related model, you just use the lower-case model name - you can see that choice is one of the available fields.
However, this still won't work; there is no __count attribute to filter against. You can add one by using annotations, but there is a simpler way: compare against None:
.exclude(choice=None)
In the Choice model set the related_name to the Question foreign key.
Example:
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='choices')
# other code..
And then your query should be something like that:
return (Question.objects
.filter(pub_date__lte=timezone.now(),
choices__isnull=False)
.order_by('-pub_date')[:5])
Note: There is no `__count' lookup. If you want to rely on counts then check the docs on this.
docs: https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_name
The _set only applies when you are using that to retrieve the related model outside of the queryset, instead, as the error suggests, you can just use choice
.exclude(choice__isnull=True)
Related
I'm new to django. I'm using a ManyToMany field in my Profile model with Membership Model.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
picture = models.ImageField(blank=True)
membership = models.ManyToManyField(MemberShip, null=True)
What I want to do is I want to get all the users who has specific membership(from membership model)
For example I want the list of all the users who has the Red Membership. I researched and found out that select_related() or prefetch_related can help in some way. but I can't understand how can I use these methods to get what I want.
I've tried this:
user_memberships_all = Profile.objects.all()
for m in user_memberships_all:
affiliate_with_membership = m.membership.select_related('user').all()
but I get an error saying Invalid field name(s) given in select_related: 'user'.
if there is another of achieving this. can you please help with that. Thank You.
To get all Users related to a specific MemberShip you can follow the OneToOneField backwards and then filter on the ManyToManyField
# Filtering on a "name" attribute of MemberShip
User.objects.filter(profile__membership__name='red')
# Using a MemberShip instance
red_membership = MemberShip.objects.get(name='red')
User.objects.filter(profile__membership=red_membership)
i have two model classes and they are related by OneToOneField like here
class Book(models.Model):
is_user_ok = models.BooleanFiled()
class Mybook(models.Model):
book = models.OneToOneField( Book, related_name="Book", null=True, blank=True, on_delete=models.SET_NULL)
now i want make a queryset filter by book field property. but here book.is_user_ok
cannot be used. how can i make this queryset filter?
queryset = Mybook.objects.filter(book.is_user_ok=True)
You are looking a common problem, what you really want to do is related_name__column_name in filter, in your case you can try
queryset = Mybook.objects.filter(book__is_user_ok=True=True)
Reference from official docs:
https://docs.djangoproject.com/en/4.0/topics/db/queries/
double underscore is used for joins as you have already set the relationship in model variety of joins work here, it is used as per the model relation.
You are using a wrong syntax. Replace (book.is_user_ok=True) with (book__is_user_ok=True) The problem is, using '.' instead of '__'. Thats the correct syntax when dealing with another model class
I have 2 models connected via M2M relation
class Paper(models.Model):
title = models.CharField(max_length=70)
authors = models.ManyToManyField(B, related_name='papers')
class Author():
name = models.CharField(max_length=70)
Is there a way to include authors as all related authors' IDs (and maybe name somehow)?
Is there a way to include papers IDs as reverse relation (and maybe title as well)?
Author.objects.all().annotate(related_papers=F('papers'))
this only adds id of one paper, first one it finds I think.
Furthermore, changing related_papers to papers gives an error:
ValueError: The annotation ‘papers’ conflicts with a field on the
model.
From what I understand in your comments, you're using DRF. I will give you 2 answers.
1) If you're talking about model serializer, you can use PrimaryKeyRelatedField :
class AuthorSerializer(serializers.ModelSerializer):
papers=serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Author
fields = ['name', 'papers']
class PaperSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
fields = '__all__'
This will return the IDs for the other side of the relationship whether you're on Paper or Author side. That will return the primary keys, not a representation of the object itself.
2) Now you're also talking about performance (e.g. database hit at each iteration).
Django (not DRF-specific) has a queryset method to handle preloading related objects. It's called prefetch_related.
For example, if you know you're going to need the relation object attributes and want to avoid re-querying the database, do as follow:
Author.objects.all().prefetch_related('papers')
# papers will be already loaded, thus won't need another database hit if you iterate over them.
Actually, it has already been implemented for you. You should include a Many-to-Many relationship to author in your Paper model like this:
class Paper(models.Model):
title = models.CharField(max_length=70)
authors = models.ManyToManyField(Author, related_name='papers')
That gives you the opportunity to add Author objects to a related set using
p.authors.add(u), assuming that p is the object of Paper model, and a is an object of Author model.
You can access all related authors of a Paper instance using p.authors.all().
You can access all related papers of an Author instance using u.papers.all().
This will return an instance of QuerySet that you can operate on.
See this documentation page to learn more.
How do I check if there are any ManyToMany field objects related to my model object?
For example, I have a model:
class Category(models.Model):
related_categories = models.ManyToManyField('self', blank=True)
I want to do something only if there are related objects existing:
if example_category.related_categories:
do_something()
I tried to do example_category.related_categories, example_category.related_categories.all(), example_category.related_categories.all().exists(), example_category.related_categories.count(), but none of these works for me.
I have no any additional conditions to filter by.
Is there any easy way to check emptiness of this field?
you should use the .exists method:
related_categories = example_category.related_categories
if related_categories.exists():
# do something
I'm following djangoproject official tutorials in part 4 it use question.choice_set Statment I don't know what is mean choice_set can anyone help me?
Can I use question.Objects for example instead of question.choice_set?
If you make a ForeignKey from Choice to Question, like:
class Choice(models.Model):
# ...
question = models.ForeignKey(Question, on_delete=models.CASCADE)
Then Django automatically creates an opposite relation. By default, the name of the relation is nameofmodel_set.
Since there can be multiple Choice objects that map on the same Question, this is a set (a set that can contain zero, one, or more objects).
So by using somequestion.choice_set, you get an ObjectManager that deals with all the Choice objects for a specific Question instance (here the somequestion).
You can then for example .filter(..) on that set, or .update(..) or write custom ORM queries. So for example somequestion.choice_set.all() will give you all the related Choices.
Sometimes the name of this reverse relation is not very nice, in that case, you can use the reated_name parameter, to give it another name, like:
class Choice(models.Model):
# ...
question = models.ForeignKey(Question,
on_delete=models.CASCADE,
related_name='options')
In case you do not want such reverse relation (for example because it would result in a lot of confusion), then you can use a '+' as related_name:
class Choice(models.Model):
# ...
# no opposite relation
question = models.ForeignKey(Question,
on_delete=models.CASCADE,
related_name='+')
modelname_set is default attribute name by which you can access reverse related objects . So in your you have model something like:
class Question(Model):
...
class Choice(Model):
question = ForeignKey(Question)
...
So if you want to get all choices related to specific question you can use followng syntax:
question.choice_set.all()
You can change attribute name to something more human readable using related_name argument:
class Choice(Model):
question = ForeignKey(Question, related_name='choices')
In this case you can now use question.choices.all() to get question's choices.