Here I'm trying to get count of each position from PunchRawData after filtering out distinct related values.
for that I need following code to work together.
queryset = PunchRawData.objects.filter(punch_type=IN, actual_clock_datetime__date=actual_clock_datetime).distinct('employee')
trade_based = queryset.values('employee__position').annotate(emp_count=Count('employee__position'))
But I get this error:
NotImplementedError: annotate() + distinct(fields) is not implemented.
How to resolve this?
Apply annotate first and then use distinct. Plus you can achieve this only using one query there is no need for another variable
queryset = PunchRawData.objects.filter(punch_type=IN, actual_clock_datetime__date=actual_clock_datetime).annotate(emp_count=Count('employee__position', distinct=True)).values('emp_count')
Hope this will work for you.
Related
I have a filter which should return a queryset with 2 objects, and should have one different field. for example:
obj_1 = (name='John', age='23', is_fielder=True)
obj_2 = (name='John', age='23', is_fielder=False)
Both the objects are of same model, but different primary key. I tried usign the below filter:
qs = Model.objects.filter(name='John', age='23').annotate(is_fielder=F('plays__outdoor_game_role')=='Fielder')
I used annotate first time, but it gave me the below error:
TypeError: QuerySet.annotate() received non-expression(s): False.
I am new to Django, so what am I doing wrong, and what should be the annotate to get the required objects as shown above?
The solution by #ktowen works well, quite straightforward.
Here is another solution I am using, hope it is helpful too.
queryset = queryset.annotate(is_fielder=ExpressionWrapper(
Q(plays__outdoor_game_role='Fielder'),
output_field=BooleanField(),
),)
Here are some explanations for those who are not familiar with Django ORM:
Annotate make a new column/field on the fly, in this case, is_fielder. This means you do not have a field named is_fielder in your model while you can use it like plays.outdor_game_role.is_fielder after you add this 'annotation'. Annotate is extremely useful and flexible, can be combined with almost every other expression, should be a MUST-KNOWN method in Django ORM.
ExpressionWrapper basically gives you space to wrap a more complecated combination of conditions, use in a format like ExpressionWrapper(expression, output_field). It is useful when you are combining different types of fields or want to specify an output type since Django cannot tell automatically.
Q object is a frequently used expression to specify a condition, I think the most powerful part is that it is possible to chain the conditions:
AND (&): filter(Q(condition1) & Q(condition2))
OR (|): filter(Q(condition1) | Q(condition2))
Negative(~): filter(~Q(condition))
It is possible to use Q with normal conditions like below:
(Q(condition1)|id__in=[list])
The point is Q object must come to the first or it will not work.
Case When(then) can be simply explained as if con1 elif con2 elif con3 .... It is quite powerful and personally, I love to use this to customize an ordering object for a queryset.
For example, you need to return a queryset of watch history items, and those must be in an order of watching by the user. You can do it with for loop to keep the order but this will generate plenty of similar queries. A more elegant way with Case When would be:
item_ids = [list]
ordering = Case(*[When(pk=pk, then=pos)
for pos, pk in enumerate(item_ids)])
watch_history = Item.objects.filter(id__in=item_ids)\
.order_by(ordering)
As you can see, by using Case When(then) it is possible to bind those very concrete relations, which could be considered as 1) a pinpoint/precise condition expression and 2) especially useful in a sequential multiple conditions case.
You can use Case/When with annotate
from django.db.models import Case, BooleanField, Value, When
Model.objects.filter(name='John', age='23').annotate(
is_fielder=Case(
When(plays__outdoor_game_role='Fielder', then=Value(True)),
default=Value(False),
output_field=BooleanField(),
),
)
Using Django and Python 3.7. I'm tryhing to write a query to give me the average of the difference between two dates. I have two fields in my model, both "DateTimeField"s, and I try to calculate the average difference like so
everything_avg = Article.objects.aggregate(
avg_score=Avg(F('removed_date') - F('created_on'), output_field=models.DateTimeField())
).filter(removed_date__isnull=False)
return everything_avg
but I end up getting this error when running the above
AttributeError: 'dict' object has no attribute 'filter'
What's the right way to get my average?
As the documentation says:
aggregate() is a terminal clause for a QuerySet that, when invoked, returns a dictionary of name-value pairs. *
aggregate method returns a dictionary, thus you need to make your filtering before it. Thus if you alter your code as following you would get your result:
everything_avg = Article.objects.filter(removed_date__isnull=False)\
.aggregate(
avg_score=Avg(
F('removed_date') - F('created_on'),
output_field=models.DateTimeField()
)
)
return everything_avg
I've got a QuerySet I'd like to filter by the count of a related_name. Currently I've got something like this:
objResults = myObjects.filter(Q(links_by_source__status=ACCEPTED),Q(links_by_source__count=1))
However, when I run this I get the following error message:
Cannot resolve keyword 'count' into field
I'm guessing that this query is operating individually on each of the links_by_source connections, therefore there is no count function since it's not a QuerySet I'm working with. Is there a way of filtering so that, for each object returned, the number of links_by_source is exactly 1?
You need to use an aggregation function to get the count before you can filter on it.
from django.db.models import Count
myObjects.filter(
links_by_source__status=ACCEPTED).annotate(link_count=Count('links_by_source')
).filter(link_count=1)
Note, you should pay attention to the order of the annotate and filter here: that query counts the number of ACCEPTED links, not sure if you want that or you want to check that the total count of all links is 1.
How can I make an order_by like this ....
p = Product.objects.filter(vendornumber='403516006')\
.order_by('-created').distinct('vendor__name')
The problem is that I have multiple vendors with the same name, and I only want the latest product by the vendor ..
Hope it makes sense?
I got this DB error:
SELECT DISTINCT ON expressions must match initial ORDER BY expressions
LINE 1: SELECT DISTINCT ON ("search_vendor"."name")
"search_product"...
Based on your error message and this other question, it seems to me this would fix it:
p = Product.objects.filter(vendornumber='403516006')\
.order_by('vendor__name', '-created').distinct('vendor__name')
That is, it seems that the DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s). So by making the column you use in distinct as the first column in the order_by, I think it should work.
Just matching leftmost order_by() arg and distinct() did not work for me, producing the same error (Django 1.8.7 bug or a feature)?
qs.order_by('project').distinct('project')
however it worked when I changed to:
qs.order_by('project__id').distinct('project')
and I do not even have multiple order_by args.
In case you are hoping to use a separate field for distinct and order by another field you can use the below code
from django.db.models import Subquery
Model.objects.filter(
pk__in=Subquery(
Model.objects.all().distinct('foo').values('pk')
)
).order_by('bar')
I had a similar issue but then with related fields. With just adding the related field in distinct(), I didn't get the right results.
I wanted to sort by room__name keeping the person (linked to residency ) unique. Repeating the related field as per the below fixed my issue:
.order_by('room__name', 'residency__person', ).distinct('room__name', 'residency__person')
See also these related posts:
ProgrammingError: when using order_by and distinct together in django
django distinct and order_by
Postgresql DISTINCT ON with different ORDER BY
I want to retrieve a sum of two fields (which are aggregations themselves) for each object in a table.
The following may describe a bit better what I'm after but results in an Unknown column in field list-Error:
items = MyModel.objects.annotate(
field1=Sum("relatedModel__someField"),
field2=Sum("relatedModel__someField")).extra(
select={"sum_field1_field2": "field1 + field2"})
I also tried using F() for the field lookups but that gives me an invalid sql statement.
Any ideas on how to solve this are much appreciated.
it this what you want?
items = MyModel.objects.extra(
select = {'sum_field1_field2': 'SUM(relatedModel__someField) + SUM(relatedModel__someField)'},
)
To make it work for many to many or for many to one (reverse) relations, you may use the following:
items = MyModel.objects.extra(
select = {'sum_field1_field2': 'SUM("relatedModel"."someField") + SUM("relatedModel"."someField")'},
)
But this will break also if you need another annotate, like for a count, because extra will add the statement to the GROUP BY clause, whereas aggregate functions are not allowed in there.