How annotate the Max value of two fields in a Django QuerySet - python

I have a model Client, how do i annotate then sort, the Max of its two fields:
from django.db import models
class Client(models.Model):
uploaded_photo_at = models.DateTimeField()
uploaded_document_at = models.DateTimeField()
The following:
Client.objects.annotate(
latest_activity_at=Max('uploaded_photo_at', 'uploaded_document_at', output_field=DateTimeField())
).order_by('latest_activity_at')
Raises this error:
django.db.utils.ProgrammingError: function max(timestamp with time zone, timestamp with time zone) does not exist
LINE 1: ...oto_at", "clients_client"."uploaded_document_at", MAX("clien...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
I am using Posgresql and Django 1.11, if that helps.

Thanks to Robert's answer i was able to find Greatest class of Django.
The following works:
from django.db.models.functions import Greatest
Client.objects.annotate(
latest_activity_at=Greatest('uploaded_photo_at', 'uploaded_document_at')
).order_by('latest_activity_at')

Hi you can use django query extra function
qs = Client.objects.extra(select={'output_field':
'GREATEST(uploaded_photo_at, uploaded_document_at)'})
.order_by('latest_activity_at')
This will return max value two fileds

Related

How can I make a field in Django models that concatenates a specific string to each record's id?

I have made a field facility_id in Django models that should concatenate a specific string "ACCTS-" on the left with each record's id on the right,
My model class is below:
class Facility(models.Model):
...
id = models.BigAutoField(primary_key=True)
facility_id = models.CharField(max_length=50, default=print(f'{"ACCTS-"}{id}'), editable=False)
...
I want to the facility_id field to be storing special and readable human friendly facility_id's of the form: ACCTS-1, ACCTS-2, ACCTS-3, ... corresponding to each individual id.
The migrations didn't throw any errors, however When I try to create the records for this table in the Django Admin, am getting an IntegrityError of:
IntegrityError at /admin/ACCTS_CLYCAS/facility/add/
NOT NULL constraint failed: ACCTS_CLYCAS_facility.facility_id
How do I fix this problem, or what could be the easiest way to implement my problem.
The migrations didn't throw any errors, however When I try to create the records for this table in the Django Admin
That makes sense, since you have set the default=None. Indeed, print(…) returns None and only prints the value to the standard output channel (stdout). It will thus not prepend the value of the id with ACCTS.
If the facility_ids are all just the id prefixed with ACCTS-, you can work with a #property instead:
class Facility(models.Model):
id = models.BigAutoField(primary_key=True)
#property
def facility_id(self):
return f'ACCTS-{self.id}'
You can also try using a post save signal.
Add blank = True to facility_id and then use a post save signal to update the value of facility_id.
You can watch this tutorial on how to use Django Signals

Django aggregation function in Hstore field

I am using djagno postgres function from
https://docs.djangoproject.com/en/3.0/ref/contrib/postgres/fields/
I need to use aggregation function in hstore field, but getting error...
Here is my models.py
def get_default_dict():
return {}
class Post(models.Model):
.................
extra_details = HStoreField(default=get_default_dict)
class Meta:
db_table = 'post'
extra_details field save like {"abc":1}, {"abc":100}, {"abc":433}
Now i have to get the post object where extra_details['abc'] value are highest ( ex. 433)
I am tring to do like
from django.db.models import Avg, Max
Post.objects.filter(id__in=[1,2,3,4,5,..]).annotate(ab=Max('extra_details__abc'))
getting error
*** django.db.utils.ProgrammingError: function max(hstore) does not exist
LINE 1: ......."statistics", MAX("post..
HINT: No function matches the given name and argument types. You might need to add
explicit type casts.
How can i use aggregate function in this situation?

DRF - filter list by DateField

I have a Ride model:
class Ride(models.Model):
driver = models.ForeignKey('auth.User', related_name='rides_as_driver')
destination=models.ForeignKey(Destination, related_name='rides_as_final_destination')
leaving_time=models.TimeField()
leaving_date=models.DateField(default=datetime.date.today)
num_of_spots=models.IntegerField()
passengers=models.ManyToManyField('auth.User', related_name="rides_as_passenger")
mid_destinations=models.ManyToManyField(Destination, related_name='rides_as_middle_destination')
and I am trying to filter the rides_as_driver field by today's date:
def get(self, request):
user=self.request.user
driverRides = user.rides_as_driver.filter(leaving_time=datetime.date.today)
The filter line throws an exception, saying:
RemovedInDjango19Warning: Passing callable arguments to queryset is deprecated.
value, lookups, used_joins = self.prepare_lookup_value(value, lookups, can_reuse, allow_joins)
I also tried with get: driverRides = user.rides_as_driver.get(leaving_time=datetime.date.today), didn't work.
How do I filter a list of objects by field value?
Thanks!
First, leaving_time is a TimeField which stores datetime.time values, while you are trying to filter by a datetime.datetime object. You have leaving_date in your code which you should apparently filter by instead.
Second, the error says that you are passing a function (datetime.date.today) as a filter argument and this is dropped in Django 1.9.
So what you want to do is:
driverRides = user.rides_as_driver.get(leaving_date=datetime.datetime.now().date())
Also check out documentation on Time zones if you have to handle users from multiple time zones in your application.

Django 1.6: How to order a query set by a computed DateTimeField

I have a project model having a DateTimeField and duration PositiveIntegerField fields.
The model also has a function days_left implementing relatively involved logic to compute the number of days left till expiry. The function returns an integer.
I want to preform a simple queryset ordering by the value returned by this function.
Project.objects.all().order_by('days_left')
However I keep getting an exception to the effect that days_left is not a field.
Is there any efficient way to do this in native SQL (maybe through views, etc..) and bypass the queryset or does there exist a django solution for such cases?
The whole code:
import datetime as nsdt
from django.db import models
from django.utils import timezone
class Project(models.Model):
name = models.CharField(max_length=128)
publish_date = models.DateTimeField()
duration_days = models.PositiveIntegerField()
def days_left(self):
t1 = timezone.now()
t2 = self.publish_date + nsdt.timedelta(days=self.duration_days)
return (t2 - t1).days if t2 > t1 else 0
if __name__ == '__main__':
print Project.objects.all().order_by('days_left')
# throws excpetion:
# django.core.exceptions.FieldError: Cannot resolve keyword 'days_left_computed' into field.
Since sorting is happening on the database level, you cannot use Django's order_by for this. Instead, you can try sorting the objects using sorted().
projects = sorted(Project.objects.all(), key=lambda x: x.days_left())
Update:
Since you have a large number of records, maybe you can use the Queryset.extra() method. Source
Another approach you may try is using django.db.models.F.
Example using F() (disclaimer: this was not tested)
from django.db.models import F
projects = Project.objects.all().order_by((F('publish_date') + nsdt.timedelta(days=F('duration_days'))) - timezone.now())

Django values get year from DateTimeField

I have a page where users can search for other users. The search is called with AJAX and the results are returned using JSON with the following code:
return HttpResponse(json.dumps({'users': list(users.values('first_name', 'last_name', 'gender', 'zip_code__city', 'zip_code__state')) }))
I have the users birthday stored in the model with birthday = models.DateTimeField(). I am trying to return just the year of the birthday with the results, but I am having trouble. Returning the whole date would work as well as I can always parse out the year later.
When I try just adding 'birthday' to the arguments in values, I get an error that it is not JSON serializable. I also tried 'birthday__year', but that returned an error that there was no such thing as 'year'.
How do I get the DateTimeField into the list?
Build a models.py method to return the year:
models.py
from django.db import models
class MyModel(models.Model):
birthday = models.DateTimeField()
def get_year(self):
return self.birthday.year
Then call this function from your views.py
You can't set a dynamic default like this, nor should you really need to store it in a database
Just make it a property (maybe even cached_property)
#property
def age(self):
return date.today().year - self.DOB.year

Categories