Annotate and .get() in Django - django

In my database I have a table card linked to a table amount, 1 card can have many amounts.
So with django I try to get a specific card and aggregate the sum of all the amounts linked. But impossible to concatenate .get() and .annotate together.
I tried this:
last_year_amount = Card.objects.get(date__date=date(today.year - 1,
today.month, today.day)).annotate(total=Sum(Amount.amount))
But of course it raises an error ''Card' object has no attribute 'annotate''.
I understand that .get() return an object an not a QuerySet so .annotate doesn't exists as a method of this object.
But how to get this object with the annotate?
Thanks for your answers

Swap the order of annotate and get.
last_year_amount = Card.objects\
.annotate(total=Sum('amount'))\
.get(date__date=date(today.year - 1, today.month, today.day))
You could also use a filter().
last_year_amount = Card.objects\
.filter(date__date=date(today.year - 1, today.month, today.day))\
.annotate(total=Sum('amount'))\
.get()
The final get() with no arguments will raise an exception if the queryset doesn't contain exactly one item.

I tried, but had another error.
Finally I had an error in the Amount.amount and in the format of get.
The solution was:
last_year_amount = Card.objects.filter(date__date=date(today.year - 1, today.month, today.day)).annotate(total=Sum('amount__amount'))[:1].get()
Which works very fine

How about going in the reverse order:
Amount.objects.filter(card__date__date=date(today.year - 1, today.month, today.day)).values('card').annotate(total=Sum('amount'))
I assumed that Amount model has a foreign key to Card model with field name of card.

Related

Overwrite field in queryset annotate

I have a django model with the fields name (string) and value (integer). Say I need to return a queryset of {name:..., value:...} objects, with each value doubled. What I am trying to do now is:
queryset.annotate(value=F('value') * 2)
However, django tells me that the field value already exists.
I also tried using extra:
queryset.annotate(value_double=F('value') * 2).extra(select={'value': 'value_double'})
but that also does not work since value_double is not a valid field.
Of course, in this case I could use something like queryset.extra(select={'value': 'value * 2'}), but I have some other, more complicated cases involving a lot of functions where I really don't want to write sql, but I'd rather find a solution in django. Again, in all of my cases, annotate works perfectly fine as long as I give the result a new name.
Say your model is XYZ with fields name and val. If you want val to contain val*2 use below queryset
x = XYZ.objects.values('name').annotate(val=F('val')*2)
print(x)
Result
<QuerySet [{'name': abc, 'val': 104},...............]
If you want queryset that return name,val and doubleval. You can use below query for same.
x = XYZ.objects.values('name','val',doubleval=F('val')*2)
print(x)
Result
<QuerySet [{'name': abc, 'val':52,'doubleval': 104},...............]
Hope this help.

Is there any way I can avoid iterating over a query set with single value?

I get a queryset object every time i want some data from models.
So when i say,
"items = Items.object.get(value=value)"
I get --
"<QuerySet [<Item-name>]>"
I have to iterate through the queryset object to get the data and I do that with
"items[0]"
Is there any way I can avoid this?
Edit: I meant "items = Items.object.filter(value=value)"
first of all items = Items.objects.get(value=value) does not return a queryset,
rather it returns an object of <Items: Items object (1)>
To get the first(or just one result) or last date from the object, do this Items.objects.first() or Items.objects.last()
To get the desired data without using its index position, then you can filter it like this Items.objects.filter(value=value)
You are mistaken. items = Items.object.get(value=value) will not give you a queryset, but an object. items = Items.object.filter(value=value)
would give you a queryset.
Filter method will always give you a queryset, because; in order to minimize the need of database hits, django considers you might add additional filters through your code. So if you not execute that queryset, e.g. by using list(your_queryset) django never hits the database.
# when you are using 'get' in your query, you don't need to iterate, directly get an access to the field values
try:
items = Items.object.get(value=value)
except Items.DoesNotExist:
items = None
if items:
print(items.value)

How do I calculate the average difference between two dates in Django?

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

difference between values() and only()

what's the difference between using:
Blabla.objects.values('field1', 'field2', 'field3')
and
Blabla.objects.only('field1', 'field2', 'field3')
Assuming Blabla has the fields in your question, as well as field4,
Blabla.objects.only('field1', 'field2', 'field3')[0].field4
will return the value of that object's field4 (with a new database query to retrieve that info), whereas
Blabla.objects.values('field1', 'field2', 'field3')[0].field4
will give
AttributeError: 'dict' object has no attribute 'field4'
This is because .values() returns a QuerySet that returns dictionaries, which is essentially a list of dicts, rather than model instances (Blabla).
The answers given so far are correct, but they don't mention some of the differences in terms of queries. I will just report them.
.get()
# User.objects.get(email='user#email.com').username
SELECT "users_user"."id", "users_user"."password", "users_user"."last_login",
"users_user"."is_superuser", "users_user"."username", "users_user"."first_name",
"users_user"."last_name", "users_user"."email", "users_user"."is_staff", "users_user"."is_active",
"users_user"."date_joined", "users_user"."name"
FROM "users_user"
WHERE "users_user"."email" = 'user#email.com'; args=('user#email.com',)
.only().get()
# User.objects.only('username').get(email='user#email.com')
SELECT "users_user"."id", "users_user"."username"
FROM "users_user"
WHERE "users_user"."email" = 'user#email.com'; args=('user#email.com',)
.values().get()
# User.objects.values('username').get(email='user#email.com')
SELECT "users_user"."username"
FROM "users_user"
WHERE "users_user"."email" = 'user#email.com'; args=('user#email.com',)
As you can see, only() will also select the id of the record. This is probably because of the fact that it will output a model that you can later use, as the other answers mentioned.
.values() gives you "less than a model"; the items it returns are closer to dictionaries than full models, which means you don't get the model attributes but you also don't have to initialize full models.
.only() restricts the field list in the SQL to specific fields you care about, but still initializes a full model; it defers loading of the other fields until you access them (if at all).
values() returns QuerySet - which when iterated returns dictionaries representing the model. It does not return model objects.
only() is a way of restricting the columns returned, and ensuring that only those columns are returned immediately - which is why it is sometimes referred to as the opposite of defer() It is the equivalent of saying SELECT foo, bar, zoo FROM rather than the normal SELECT [all columns] FROM. It will return a QuerySet that can further be chained.

Difference between Django's filter() and get() methods

What is the difference between
mymodel=model.objects.get(name='pol')
and
mymodel=model.objects.filter(name='pol')
The Django QuerySet docs are very clear on this:
get(**kwargs)¶
Returns the object matching the given
lookup parameters, which should be in
the format described in Field lookups.
get() raises MultipleObjectsReturned
if more than one object was found. The
MultipleObjectsReturned exception is
an attribute of the model class.
get() raises a DoesNotExist exception
if an object wasn't found for the
given parameters. This exception is
also an attribute of the model class.
filter(**kwargs)
Returns a new QuerySet containing objects that match the given lookup parameters.
Basically use get() when you want to get a single unique object, and filter() when you want to get all objects that match your lookup parameters.
Note that behind the scenes the django get() method runs the filter() method, but checks that the filter results set is exactly one record
Also, on a side note, assuming pol is not available:
if mymodel=model.objects.get(name='pol').exists()==False:
print "Pol does not exist"
you will get:
AttributeError: 'Model' object has no attribute 'exists'
but:
if mymodel=model.objects.filter(name='pol').exists()==False:
print "Pol does not exist"
you will get: Pol does not exist.
I.e. If you want to run some code depending on whether a single object can be found, use filter. For some reason exists() works on QuerySet but not the specific object returned with get.
get() returns an object that matches lookup criterion.
filter() returns a QuerySet that matche lookup criterion.
For example, the following
Entry.objects.filter(pub_date__year=2006)
is equivalent to
Entry.objects.all().filter(pub_date__year=2006)
which means filter() is slightly expensive operation if the model class has a large number of objects, whereas get() is direct approach.
source: Django making queries
Another difference:
Because 'get' returns an object, the method 'update' cannot be called on the object; except a model method (which shouldn't be done, to avoid overriding), was written.
However, querying with 'filter', gives you the ability to update a preferred record.
e.g: say a model; 'Product' exists in your app; then you could do thus:
old_product_name = Product.objects.filter(product_name="green-peas")
old_product_name.update(product_name="skewed-peas")
That of course, isn't possible when you query with 'get'.
Django's get and filter methods are commonly used by django models, and are distinguished here.
Define 2 models.
class Student(models.Model):
Name = models.CharField('name', max_length=15, default='')
Age = models.CharField('age', max_length=15, default='')
class Book(models.Model):
student = models.ForeignKey(Student)
A.django get method:
django's get method is to get a matching result from the database, return an object, if the record does not exist, it will report an error. For example, if there is a record in my database, the value of the record name is django123, I use student = Student . objects . get ( name = ’ django123 ’ ),
returns a record object, which you can view through student . _ _ dict _ _, which returns a dictionary form, {' key ' : valeus}, key is the field The name, while values ​​are the contents of the value.
Using the get method to query a record that does not exist in the database, the program will report an error.
For example: student = Student . objects . get ( name = ’ django ’ ), obviously this 'django ' does not exist in the database, it will report an error.
If you use django's get to get the data of the associated table, if the data of the key table is more than 2, it will report an error.
If there is a record in the student table:
d name age
1 python 24
Book table:
id student_id
1 1
2 1
student = Student.objects.get(name='python')
book = Book.objects.get(student)
The result will be reported because the book table has 2 records that match the student table.
Two.django filter method:
django's filter method is to get a matching result from the database, return a list of objects, if the record does not exist, it will return [ ].
If the database has a record, the value of the record name is python123, using student = Student . objects .filter ( name = ’ python123 ’ ). Returning student is a list of objects. It can be seen that student [ 0 ] is the same as the student returned by the get method above.
If you use django's get to get the data of the associated table, no matter how many records in the associated table, no error will be reported.
django In addition to the powerful model, forms and templates are also very powerful.
filter has the function of caching data. The first time you query the database and generate the cache, the next time you call the filter method, you can directly get the cached data, and the get method is directly queried every time in database.
mymodel=model.objects.get(name='pol')
# OR
mymodel=model.objects.filter(name='pol')
Case 1: Suppose we have only one record that matches the name field pol. 
get() will return on single objects whereas filter() will also return a single object in the list.
Case 2: Suppose we have more than one records that match the name field pol.
get() will raise MultipleObjectsReturned but in the case of filter(), it will return a list of objects.
Case 3: Suppose we have no record found that matches the name field pol.
get() raises a DoesNotExist exception but in the case of filter(), it will return an empty list.
if you know it's one object that matches your query, use "get". It will fail if it's more than one and gives the error like this
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 143, in get
return self.get_query_set().get(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 407, in get
(self.model._meta.object_name, num))
MultipleObjectsReturned: get() returned more than one Poll -- it returned 2!
Otherwise use "filter", which gives you a list of objects.
Model = Employee
Employee : name,age,loc
Get:
Employee.objects.get(id=1)
It will through error if given object is not there
Filter :
Employee.objects.filter(id=1)
]>
It will return empty Queryset if given object is not there