I have a model in which I have a ForeignKey and an IntegerField.
I want to sum the integer field grouped by the foreign key but the foreign key can have many values. I am only interested in knowing if the foreign key has a 'real value' or is none. So the foreign key should be interpreted as a boolean.
I could make two queries:
a = Model.objects.filter(parent=None).aggregate(Sum('amount'))
b = Model.objects.exclude(parent=None).aggregate(Sum('amount'))
but isn't it less memory demanding to make something like
c = Model.objects.values('parent__as_bool').annotate(Sum('amount'))
if it's possible?
You can always use .extra, like this:
.extra(select={'parent_is_null': "parent is NULL"})
see docs for more examples
Your second option isn't valid because you need to filter the queryset before asking for values, and to specify what you're calling your annotation. As far as treating a foreignkey as a boolean is concerned you're looking for isnull. So you end with something like:
c = Model.objects.filter(parent__isnull=False).values().annotate(amount_sum=Sum('amount'))
Related
I am getting data objects from Django models using
tabledata=Entity.objects.filter(quarter=1)
Using this method, I am able to extract the values of the objects specified by the foreign key like so
tabledata[0].creator.name
However when I changed the code to
tabledata=Entity.objects.filter(quarter=1).values()
I can extract only foreign key values but not the values of the object data linked with the foreign key. Something like
tabledata[0][creator][name] does not work
Is there a way to extract the values this way?
You can use lookup in .values() like this:
entities = Entity.objects.filter(quarter=1).values('creator__name')
print(entities[0]['creator__name'])
You can fetch other fields too if you need:
Entity.objects.filter(quarter=1).values('creator__name', 'direct_field', 'another_direct_field')
This is one of the many reasons why using .values() [Django-doc] is not a good idea: it erodes the logical layer of the model.
You can use .annotate(…) [Django-doc] to add the name to the values:
from django.db.models import F
tabledata = Entity.objects.filter(quarter=1).annotate(
creator_name=F('creator__name')
).values()
Then it will appear under the 'creator_name' key in the dictionary.
But using .values() is often only useful in specific usecases. For example a GROUP BY on a specific value, or in a subquery. You should make use of serializers if you want to make JSON for a given model.
I'm working on a Django project on which i have a queryset of a 'A' objects ( A.objects.all() ), and i need to annotate multiple fields from a 'B' objects' Subquery. The problem is that the annotate method can only deal with one field type per parameter (DecimalField, CharField, etc.), so, in order to annotate multiple fields, i must use something like:
A.objects.all().annotate(b_id =Subquery(B_queryset.values('id')[:1],
b_name =Subquery(B_queryset.values('name')[:1],
b_other_field =Subquery(B_queryset.values('other_field')[:1],
... )
Which is very inefficient, as it creates a new subquery/subselect on the final SQL for each field i want to annotate. I would like to use the same Subselect with multiple fields on it's values() params, and annotate them all on A's queryset. I'd like to use something like this:
b_subquery = Subquery(B_queryset.values('id', 'name', 'other_field', ...)[:1])
A.objects.all().annotate(b=b_subquery)
But when i try to do that (and access the first element A.objects.all().annotate(b=b_subquery)[0]) it raises an exception:
{FieldError}Expression contains mixed types. You must set output_field.
And if i set Subquery(B_quer...[:1], output_field=ForeignKey(B, models.DO_NOTHING)), i get a DB exception:
{ProgrammingError}subquery must return only one column
In a nutshell, the whole problem is that i have multiple Bs that "belongs" to a A, so i need to use Subquery to, for every A in A.objects.all(), pick a specific B and attach it on that A, using OuterRefs and a few filters (i only want a few fields of B), which seens a trivial problem for me.
Thanks for any help in advance!
What I do in such situations is to use prefetch-related
a_qs = A.objects.all().prefetch_related(
models.Prefetch('b_set',
# NOTE: no need to filter with OuterRef (it wont work anyway)
# Django automatically filter and matches B objects to A
queryset=B_queryset,
to_attr='b_records'
)
)
Now a.b_records will be a list containing a's related b objects. Depending on how you filter your B_queryset this list may be limited to only 1 object.
I have a table called user_info. I want to get names of all the users. So the table has a field called name. So in sql I do something like
SELECT distinct(name) from user_info
But I am not able to figure out how to do the same in django. Usually if I already have certain value known, then I can do something like below.
user_info.objects.filter(name='Alex')
And then get the information for that particular user.
But in this case for the given table, I want to get all the name values using django ORM just like I do in sql.
Here is my django model
class user_info(models.Model):
name = models.CharField(max_length=255)
priority = models.CharField(max_length=1)
org = models.CharField(max_length=20)
How can I do this in django?
You can use values_list.
user_info.objects.values_list('name', flat=True).distinct()
Note, in Python classes are usually defined in InitialCaps: your model should be UserInfo.
You can use values_list() as given in Daniel's answer, which will provide you your data in a list containing the values in the field. Or you can also use, values() like this:
user_info.object.values('name')
which will return you a queryset containing a dictionary. values_list() and values() are used to select the columns in a table.
Adding on to the accepted answer, if the field is a foreign key the id values(numerical) are returned in the queryset. Hence if you are expecting other kinds of values defined in the model of which the foreign key is part then you have to modify the query like this:
`Post.objects.values_list('author__username')`
Post is a model class having author as a foreign key field which in turn has its username field:
Here, "author" field was appended with double undersocre followed by the field "name", otherwise primary key of the model will be returned in queryset. I assume this was #Carlo's doubt in accepted answer.
is it possible to follow ForeignKey relationships backward for entire querySet?
i mean something like this:
x = table1.objects.select_related().filter(name='foo')
x.table2.all()
when table1 hase ForeignKey to table2.
in
https://docs.djangoproject.com/en/1.2/topics/db/queries/#following-relationships-backward
i can see that it works only with get() and not filter()
Thanks
You basically want to get QuerySet of different type from data you start with.
class Kid(models.Model):
mom = models.ForeignKey('Mom')
name = models.CharField…
class Mom(models.Model):
name = models.CharField…
Let's say you want to get all moms having any son named Johnny.
Mom.objects.filter(kid__name='Johnny')
Let's say you want to get all kids of any Lucy.
Kid.objects.filter(mom__name='Lucy')
You should be able to use something like:
for y in x:
y.table2.all()
But you could also use get() for a list of the unique values (which will be id, unless you have a different specified), after finding them using a query.
So,
x = table1.objects.select_related().filter(name='foo')
for y in x:
z=table1.objects.select_related().get(y.id)
z.table2.all()
Should also work.
You can also use values() to fetch specific values of a foreign key reference. With values the select query on the DB will be reduced to fetch only those values and the appropriate joins will be done.
To re-use the example from Krzysztof Szularz:
jonny_moms = Kid.objects.filter(name='Jonny').values('mom__id', 'mom__name').distinct()
This will return a dictionary of Mom attributes by using the Kid QueryManager.
I want to create a new Django ORM object with three foreign keys. I got the IDs of the foreign rows already, and I mean - that's all I need to fill the foreign key columns in my new row, right? However, I don't seem able to create the new row without hitting the DB three times to instantiate objects out of those IDs.
So what I need to do:
foreign_object = models.ForeignObject.get(pk=foreign_object_id)
a = models.Object1.get_or_create(f = foreign_object)
What I'd like to do:
a = models.Object1.get_or_create(f_id = foreign_object_id)
f_id however is not a field Django recognizes. If I just assign foreign_object_id to f (I think I recall this works in some cases), Django complains that it wants a ForeignObject instance instead of an int.
Any way to do this?
You need to use the double-underscore notation in this case
eg
a = models.Object1.get_or_create(f__pk=foreign_object_id)