Django aggregation function in Hstore field - python

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?

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 REST API query on related field

I have 3 models, Run, RunParameter, RunValue:
class Run(models.Model):
start_time = models.DateTimeField(db_index=True)
end_time = models.DateTimeField()
class RunParameter(models.Model):
parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)
class RunValue(models.Model):
run = models.ForeignKey(Run, on_delete=models.CASCADE)
run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
value = models.FloatField(default=0)
class Meta:
unique_together=(('run','run_parameter'),)
A Run can have a RunValue, which is a float value with the value's name coming from RunParameter (which is basically a table containing names), for example:
A RunValue could be AverageTime, or MaximumTemperature
A Run could then have RunValue = RunParameter:AverageTime with value X.
Another Run instance could have RunValue = RunParameter:MaximumTemperature with value Y, etc.
I created an endpoint to query my API, but I only have the RunParameter ID (because of the way you can select which parameter you want to graph), not the RunValue ID directly. I basically show a list of all RunParameter and a list of all Run instances, because if I showed all instances of RunValue the list would be too long and confusing, as instead of seeing "Maximum Temperature" you would see:
"Maximum Temperature for Run X"
"Maximum Temperature for Run Y"
"Maximum Temperature for Run Z", etc. (repeat 50+ times).
My API view looks like this:
class RunValuesDetailAPIView(RetrieveAPIView):
queryset = RunValue.objects.all()
serializer_class = RunValuesDetailSerializer
permission_classes = [IsOwnerOrReadOnly]]
And the serializer for that looks like this:
class RunValuesDetailSerializer(ModelSerializer):
run = SerializerMethodField()
class Meta:
model = RunValue
fields = [
'id',
'run',
'run_parameter',
'value'
]
def get_run(self, obj):
return str(obj.run)
And the URL just in case it's relevant:
url(r'^run-values/(?P<pk>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),
Since I'm new to REST API, so far I've only dealt with having the ID of the model API view I am querying directly, but never an ID of a related field. I'm not sure where to modify my queryset to pass it an ID to get the appropriate model instance from a related field.
At the point I make the API query, I have the Run instance ID and the RunParameter ID. I would need the queryset to be:
run_value = RunValue.objects.get(run=run_id, run_parameter_id=param_id)
While so far I've only ever had to do something like:
run_value = RunValue.objects.get(id=value_id) # I don't have this ID
If I understand correctly, you're trying to get an instance of RunValue with only the Run id and the RunParameter id, i.e. query based on related fields.
The queryset can be achieved with the following:
run_value = RunValue.objects.get(
run__id=run_id,
run_parameter__id=run_parameter_id
)
Providing that a RunValue instance only ever has 1 related Run and RunParameter, this will return the instance of RunValue you're after.
Let me know if that's not what you mean.
The double underscore allows you to access those related instance fields in your query.
Well its pretty simple, all you have to do is override the get_object method, for example(copy pasted from documentation):
# view
from django.shortcuts import get_object_or_404
class RunValuesDetailAPIView(RetrieveAPIView):
queryset = RunValue.objects.all()
serializer_class = RunValuesDetailSerializer
permission_classes = [IsOwnerOrReadOnly]]
lookup_fields = ["run_id", "run_parameter_id"]
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
# url
url(r'^run-values/(?P<run_id>\d+)/(?P<run_parameter_id>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),
But one big thing you need to be careful, is not to have duplicate entries with same run_id and run_parameter_id, then it will throw errors. To avoid it, either use unique_together=['run', 'run_parameter'] or you can use queryset.filter(**filter).first() instead of get_object_or_404 in the view. But second option will produce wrong results when duplicate entries are created.

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

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

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 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