How to query for count? - django

I've got a query,
Bid.objects.filter(shipment=shipment, status=BidStatuses.ACCEPTED, user=request.user, items__count=0).exists()
The part that doesn't work is items__count=0. Bids have a many-to-many relationship with items. I need to check if this bid has 0 items. How can I do that?

Aggregation.
http://docs.djangoproject.com/en/1.2/topics/db/aggregation/
see the doc upon, read the sample,you will find the answer

For the record (there is already an accepted answer with a link to Django aggregation docs), what OP needs is:
Bid.objects.annotate(item_num=models.Count('items')).filter(shipment=shipment, status=BidStatuses.ACCEPTED, user=request.user, item_num=0).exists()

Related

Django annotate Avg of foreign model

Two models, article and review, relationship is one to many (one article has many reviews). Some articles don't have any review.
I want to order articles by review ratings, therefore I use the annotate with AVG:
ArticleQueryset.annotate(rating=models.Avg('reviews__rating')).order_by('-rating')
The issue is that the articles without reviews the rating value is False and somehow that comes before the maximum rating. The result is that the first results don't have any rating, then the highest rated articles show up.
Use nulls_last=True in order_by() method as
ArticleQueryset.annotate(
rating=models.Avg('reviews__rating')
).order_by(models.F('rating').desc(nulls_last=True))

How to write query of group by

I have model named IssueFlags with columns:
id, created_at, flags_id, issue_id, comments
I want to get data of unique issue_id (latest created) with info about flags_id, created_at and comments
By sql it's working like this:
SELECT created_at, flags_id, issue_id, comments
FROM Issues_issueflags
group by issue_id
How to do the same in Django? I tried to wrote sth in shell, but there is no attribute group by
IssueFlags.objects.order_by('-created_at')
This above return me only the list of ordered data.
Try doing this way:
from django.db.models import Count
IssueFlags.objects.values('created_at', 'flags_id', 'issue_id', 'comments').order_by('-created_at').annotate(total=Count('issue_id'))
I have written annotate(total=Count('issue_id')) assuming that you would have multiple entries of unique issue_id (Note that you can do all possible types of aggregations like Sum, Count, Max, Avg inside . Also, there already exists answers for, doing group by in django. Also have a look at this link or this link. Also, read this django documentation to get a clear idea on when to place values() before annotate() and when to place it after, and then implement the learning as per your requirement.
Would be happy to help if you have any further doubts.

Django multiple annotations with filter

Can anyone help me with this
qs = Vine.objects.annotate(votos_count=Count('votomoderacion')).\
annotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1").\
annotate(votos_no_ok=Count('votomoderacion')).filter(votomoderacion__voto="0")
The problem is that the filters affects to all the annotations, and i want to filter every single annotation separately.
I hope i've been clair enough with my question.
Thank you!
You have to understand that what you are doing is chaining filters.
First you had a queryset with annotated votes count likeannotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1").
Then you annotated votes_ok with it and filterered it like annotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1"), which gave you another filtered queryset.
But after that, you added another filter annotate(votos_no_ok=Count('votomoderacion')).filter(votomoderacion__voto="0"), which filtered the queryset which you got from previous filter. so, in this case, you didn't get your desired result.
So better if you separate them. Like:
total_votes= Vine.objects.annotate(votos_count=Count('votomoderacion'))
yes_votes= Vine.objects.annotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1")
no_votes= Vine.objects.annotate(votos_no_ok=Count('votomoderacion')).filter(votomoderacion__voto="0")
To join those queryset:
from itertools import chain
allvotes = list(chain(total_votes, yes_votes, no_votes))

Django QuerySet access foreign key field directly, without forcing a join

Suppose you have a model Entry, with a field "author" pointing to another model Author. Suppose this field can be null.
If I run the following QuerySet:
Entry.objects.filter(author=X)
Where X is some value. Suppose in MySQL I have setup a compound index on Entry for some other column and author_id, ideally I'd like the SQL to just use "author_id" on the Entry model, so that it can use the compound index.
It turns out that Entry.objects.filter(author=5) would work, no join is done. But, if I say author=None, Django does a join with Author, then add to the Where clause Author.id IS NULL. So in this case, it can't use the compound index.
Is there a way to tell Django to just check the pk, and not follow the link?
The only way I know is to add an additional .extra(where=['author_id IS NULL']) to the QuerySet, but I was hoping some magic in .filter() would work.
Thanks.
(Sorry I was not clearer earlier about this, and thanks for the answers from lazerscience and Josh).
Does this not work as expected?
Entry.objects.filter(author=X.id)
You can either use a model or the model id in a foreign key filter. I can't check right yet if this executes a separate query, though I'd really hope it wouldn't.
If do as you described and do not use select_related() Django will not perform any join at all - no matter if you filter for the primary key of the related object or the related itself (which doesn't make any difference).
You can try:
print Entry.objects.(author=X).query
Assuming that the foreign key to Author has the name author_id, (if you didn't specify the name of the foreign key column for ForeignKey field, it should be NAME_id, if you specified the name, then check the model definition / your database schema),
Entry.objects.filter(author_id=value)
should work.
Second Attempt:
http://docs.djangoproject.com/en/dev/ref/models/querysets/#isnull
Maybe you can have a separate query, depending on whether X is null or not by having author__isnull?
Pretty late, but I just ran into this. I'm using Q objects to build up the query, so in my case this worked fine:
~Q(author_id__gt=0)
This generates sql like
NOT ("author_id" > 0 AND "author_id" IS NOT NULL)
You could probably solve the problem in this question by using
Entry.objects.exclude(author_id__gt=0)

How to filter/exclude inactive comments from my annotated Django query?

I'm using the object_list generic view to quickly list a set of Articles. Each Article has comments attached to it. The query uses an annotation to Count() the number of comments and then order_by() that annotated number.
'queryset': Article.objects.annotate(comment_count=Count('comments')).order_by('-comment_count'),
The comments are part of the django.contrib.comments framework and are attached to the model via a Generic Relationship. I've added an explicit reverse lookup to my Article model:
class Article(models.Models):
...
comments = generic.GenericRelation(Comment, content_type_field='content_type', object_id_field='object_pk')
The problem is, this counts "inactive" comments; ones that have is_public=False or is_removed=True. How can I exclude any inactive comments from being counted?
The documentation for aggregations explains how to do this. You need to use a filter clause, making sure you put it after the annotate clause:
Article.objects.annotate(comment_count=Count('comments')).filter(
comment__is_public=True, comment__is_removed=False
).order_by('-comment_count')