In my model there are 10 fields, out of which below four I need to group on,
department
city
state
zip
And then get count of records which has same combination of these values
Example
IT|Portland|Oregon|11111 => 100
I tried annotate however it is not giving me desired results. Please advice
from django.db.models import Count
YourModel.objects.values('department', 'city', 'state', 'zip').annotate(count=Count('id'))
Related
In Annotate I am trying to get the count of quires for which is_healthy is True but I am getting an Error The annotation 'id' conflicts with a field on the model.
Any solution to solve this? and why is this causing how can i resolve this?
DeviceHealthHistory.objects.filter(**filter_data).values(
id = F('id'),
).annotate(
healthy_count=Count('id', filter=Q(is_healthy=True)),
)
If you are just looking for count then you use count function fo queryset:
DeviceHealthHistory.objects.filter(**filter_data).filter(is_healthy=True).count()
To get other fields along with the count.
DeviceHealthHistory.objects.filter(**filter_data).values(
'other_field1'
).annotate(
healthy_count=Count('id', filter=Q(is_healthy=True)),
)
You should count with:
DeviceHealthHistory.objects.filter(**filter_data, is_healthy=True).count()
This will filter on the **filter_data and also ensure that it only counts records with is_healthy=True. We then count the number of records.
If you want to "group by" a certain field, like patient_id, you can work with:
DeviceHealthHistory.objects.filter(**filter_data).values('patient_id').annotate(
n=Count('pk', filter=Q(is_healthy=True))
).order_by('patient_id')
This will produce a queryset of dictionaries with 'patient_id' and 'n' as keys, and the patient and the corresponding counts as values.
TAssignment model has many entries related to TSlot model like for 1 pk of TSlot model there are many entries in TAssignment model.Now this queries outputs values from Tslot table and also latest related created on and updated on from Tassignment table.But what i want is latest value of
'assignment_Slot__created_on' and 'assignment_Slot__updated_on' when assignment_Slot__is_deleted=False.
QUESTION: How to add "assignment_Slot__is_deleted=False" condition along with 'assignment_Slot__created_on' and 'assignment_Slot__updated_on' inside annotate without duplicating results.
** assignment_Slot here is related name
TSlot.objects.filter(request__id=request_id, is_deleted=False
).values("slot_date", "type_of_work", "reason_for_less_assign", "request_id","slot", "remarks",
slot_id=F("id"), request_status=F('request__request_status')).annotate(
assigned_on=Max('assignment_Slot__created_on'), modified_on =Max('assignment_Slot__modified_on'))
Add a filter to your annotations, see filtering on annotations
from django.db.models import Max, Q, DateField
TSlot.objects.filter(...).annotate(
assigned_on=Max('assignment_Slot__created_on', filter=Q(assignment_Slot__is_deleted=False), output_field=DateField()),
modified_on=Max('assignment_Slot__modified_on', filter=Q(assignment_Slot__is_deleted=False), output_field=DateField())
)
I have a table, lets call it as DummyTable.
It has fields - price_effective, store_invoice_updated_date, bag_status, gstin_code.
Now I want to get the output which does a group by of - month, year from the field store_invoice_updated_date and gstin_code.
Along with that group by I wanna do thse calculations -
Sum of price_effective as 'forward_price_effective' if the bag_status is other than 'return_accepted' or 'rto_bag_accepted'. Dont know how to do an exclude here i.e. using a filter in annotate
Sum of price effective as 'return_price_effective' if the bag_status is 'return_accepted' or 'rto_bag_accepted'.
A field 'total_price' that subtracts the 'return_price_effective' from 'forward_price_effective'.
I have formulated this query, which doesn't work
from django.db.models.functions import TruncMonth
from django.db.models import Count, Sum, When, Case, IntegerField
DummyTable.objects.annotate(month=TruncMonth('store_invoice_updated_date'), year=TruncYear('store_invoice_updated_date')).annotate(forward_price_effective=Sum(Case(When(bag_status__in=['delivery_done']), then=Sum(forward_price_effective)), output_field=IntegerField()), return_price_effective=Sum(Case(When(bag_status__in=['return_accepted', 'rto_bag_accepted']), then=Sum('return_price_effective')), output_field=IntegerField())).values('month','year','forward_price_effective', 'return_price_effective', 'gstin_code')
Solved it by multiple querysets.
Just couldnt find out a way to appropriately use 'Case' with 'When' with 'filter' and 'exclude'.
basic_query = BagDetails.objects.filter(store_invoice_updated_date__year__in=[2018]).annotate(month=TruncMonth('store_invoice_updated_date'), year=TruncYear('store_invoice_updated_date') ).values('year', 'month', 'gstin_code', 'price_effective', 'company_id', 'bag_status')
forward_bags = basic_query.exclude(bag_status__in=['return_accepted', 'rto_bag_accepted']).annotate(
Sum('price_effective')).values('year', 'month', 'gstin_code', 'price_effective', 'company_id')
return_bags = basic_query.filter(bag_status__in=['return_accepted', 'rto_bag_accepted']).annotate(
Sum('price_effective')).values('month', 'gstin_code', 'price_effective', 'company_id')
I found some solutions here and in the django documentation, but I could not manage to make one query work the way I wanted.
I have the following model:
class Inventory(models.Model):
blindid = models.CharField(max_length=20)
massug = models.IntegerField()
I want to count the number of Blind_ID and then sum the massug after they were grouped.
My currently Django ORM
samples = Inventory.objects.values('blindid', 'massug').annotate(aliquots=Count('blindid'), total=Sum('massug'))
It's not counting correctly (it shows only one), thus it 's not summing correctly. It seems it is only getting the first result... I tried to use Count('blindid', distinct=True) and Count('blindid', distinct=False) as well.
This is the query result using samples.query. Django is grouping by the two columns...
SELECT "inventory"."blindid", "inventory"."massug", COUNT("inventory"."blindid") AS "aliquots", SUM("inventory"."massug") AS "total" FROM "inventory" GROUP BY "inventory"."blindid", "inventory"."massug"
This should be the raw sql
SELECT blindid,
Count(blindid) AS aliquots,
Sum(massug) AS total
FROM inventory
GROUP BY blindid
Try this:
samples = Inventory.objects.values('blindid').annotate(aliquots=Count('blindid'), total=Sum('massug'))
I have two models:
Base_Activity:
some fields
User_Activity:
user = models.ForeignKey(settings.AUTH_USER_MODEL)
activity = models.ForeignKey(Base_Activity)
rating = models.IntegerField(default=0) #Will be -1, 0, or 1
Now I want to query Base_Activity, and sort the items that have the most corresponding user activities with rating=1 on top. I want to do something like the query below, but the =1 part is obviously not working.
activities = Base_Activity.objects.all().annotate(
up_votes = Count('user_activity__rating'=1),
).order_by(
'up_votes'
)
How can I solve this?
You cannot use Count like that, as the error message says:
SyntaxError: keyword can't be an expression
The argument of Count must be a simple string, like user_activity__rating.
I think a good alternative can be to use Avg and Count together:
activities = Base_Activity.objects.all().annotate(
a=Avg('user_activity__rating'), c=Count('user_activity__rating')
).order_by(
'-a', '-c'
)
The items with the most rating=1 activities should have the highest average, and among the users with the same average the ones with the most activities will be listed higher.
If you want to exclude items that have downvotes, make sure to add the appropriate filter or exclude operations after annotate, for example:
activities = Base_Activity.objects.all().annotate(
a=Avg('user_activity__rating'), c=Count('user_activity__rating')
).filter(user_activity__rating__gt=0).order_by(
'-a', '-c'
)
UPDATE
To get all the items, ordered by their upvotes, disregarding downvotes, I think the only way is to use raw queries, like this:
from django.db import connection
sql = '''
SELECT o.id, SUM(v.rating > 0) s
FROM user_activity o
JOIN rating v ON o.id = v.user_activity_id
GROUP BY o.id ORDER BY s DESC
'''
cursor = connection.cursor()
result = cursor.execute(sql_select)
rows = result.fetchall()
Note: instead of hard-coding the table names of your models, get the table names from the models, for example if your model is called Rating, then you can get its table name with Rating._meta.db_table.
I tested this query on an sqlite3 database, I'm not sure the SUM expression there works in all DBMS. Btw I had a perfect Django site to test, where I also use upvotes and downvotes. I use a very similar model for counting upvotes and downvotes, but I order them by the sum value, stackoverflow style. The site is open-source, if you're interested.