How to parameterize django aggregation? - django

I want to do something like
query.annotate(Count('foreign_model_relation', somefield_from_foreign_model=some_value))
That means, i want to count, how many objects from another queryset are pointing to this object. The difference between using something like filter(in=other_queryset) is, that i would like to combine this in one query, to avoid generating one query per object.
Simplified Models:
Group
Object
group (Group)
Vote
object (Object)
up (Boolean)
Now i want to query the up/down count of all Objects for one Group, with one or two queries, not with one/two queries per Object.

You can do this with two queries:
YourObject.objects.filter(vote__up=True, group=some_group).annotate(total_votes_up=Count('vote'))
YourObject.objects.filter(vote__up=False, group=some_group).annotate(total_votes_down=Count('vote'))
But I think that should exist some more elegante way to do this.

Related

It is good practice to get all object in RetrieveUpdateDestroy Method?

Why we need to get all object in RetrieveUpdateDestroy Method?
In real project can I do it just like this Without fear even if there is large data?
Why [do] we need to get all object[s] in [a] RetrieveUpdateDestroy [view]?
We don't: the queryset is not evaluated. This is only used as a "parent" queryset to make querysets to retrieve, update, and delete a single object.
Indeed, for a retrieve method, it will add .get(pk=some_pk) at the end, and thus make a query to retrieve that single object.
The queryset can be used to filter certain items, to prevent retrieving, updating and removing certain objects for example. You can for example use queryset = Student.objects.filter(active=True) to only be able to retrieve active Students.

How can I annotate another annotate group by query in Django?

I have two queries:
Proyecto.objects.filter().order_by('tipo_proyecto')
Proyecto.objects.values('tipo_proyecto').annotate(total=Sum('techo_presupuestario'))
How can I make this in only one query? I want that the first query contains an annotate data that represents all sums of techo_presupuestario, depending on your tipo_proyecto. Is this posible?
If I understand you correct, you'd like to add a conditionally aggregated sum over one field to each object, so you get each object with a sum fitting to its tipo_proyecto. Right?
I don't know, if this makes sense, but it could be done anyway using Subquery:
from django.db.models import Sum, Subquery, OuterRef
sq = Subquery(Proyecto.objects.filter(tipo_proyecto=OuterRef("tipo_proyecto")).values("tipo_proyecto").annotate(techoSum=Sum("techo_presupuestario")).values("techoSum"))
Proyecto.objects.all().annotate(tipoTechoSum = sq).order_by('tipo_proyecto')
Nonetheless, I wouldn't recommend this, as it puts some heavy load on your database. (In MySQL there will be an nested SELECT statement referring to the same table, which might be pretty unpleasant depending on the table's size.)
I'd say the better approach is to "collect" your aggregated sums separately and add the values to the model objects in your code.

Apply Q object to one object

I have a complicated query in a Django model and I want to do two things:
Get all objects that satisify the query
Check if one object satisfies the query
To do (1), I have a Q object encoding the query, and I just do
Model.objects.filter(THE_QUERY)
The query is something like
THE_QUERY = Q(field_1__isnull=False) & Q(field_2__gte=2) & Q(field3=0)
But I don't know how to reuse the query in THE_QUERY for (2). I want to have the predicate of the query in just one place and use that information to do (1) and (2), so that, if I ever have to change the query, both actions would do as expected.
Is there a way to put the query in just one place?
Model.objects.filter(THE_QUERY) returns an unevaluated queryset. You can extend this with extra conditions - in this case, you can add a filter to a specific ID and then an exists() call.
Model.objects.filter(THE_QUERY).filter(pk=my_object_id).exists()

Doctrine ORM, Coalesce in JoinColumn

Do we at this moment have a way to use coalesce in the join column for relations?
For example a car has many parts. A car can have a relation to itself. I want to make demo cars, which refer to another car (the original car). But i do not want to copy all the parts of the car. So i would like to join using Coalesce. join part.car_id = coalesce(car.car_id, car.id). So we would use the coalesce to first check if the car as a car_id, referring to the original car, if so, its a demo car and we use the car id of the original car. If not than use the car's own id. For example when calling the original car.
If this would not be possible using the Annotations. Would it be possible in a different way?
It is not possible to define conditions on doctrine association. Association is always defined between concrete entities and fields.
It also doesn't work with constrains in relational databases.
I think you should use different design to achieve it. I would recommend to introduce new entity Model and associate parts to this entity and then have a Car which is also associated to the Model.

Filtered annotations without removing results

Consider a model and a query using annotations, for example the following example from the Django documentation:
http://docs.djangoproject.com/en/dev/topics/db/aggregation/
Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))
The result of this query will only contain objects matching the filter (i.e. has a book_rating greater than 3.0), and these objects has been annotated. But what if I want the query to contain all objects, but only annotate objects which matches a filter (or for example annotate them with 0)? Or is this even possible?
No, you can't do that - because that's not how the underlying SQL works.
The only thing I can think of is to do two queries, one with the filter/annotation and one without, then iterate through them in Python, appending the annotation to the matching objects from the non-filtered list.