Filtering objects by timezone aware dates - django

Let's say I have TIME_ZONE variable in settings set to 'Europe/Prague' and also USE_TZ set to True. I also have some data stored in Example:
id timestamp
1 2012-07-27T00:00:00+02:00
2 2018-03-11T02:00:00+01:00
3 2013-11-04T14:08:40+01:00
This is what I'm trying to achieve:
Extract all dates from those data
Filter those data date by date and perform some other action on them
For extracting dates I use either Example.dates('timestamp', 'day') or Example.annotate(date=TruncDay('timestamp')).values('date').
Now here is the difference: for first object from example above (with timestamp=2012-07-27T00:00:00+02:00), date returned by first approach is 2012-07-27, whereas for second approach it is 2012-07-26.
I would like filter to be timezone aware, so I'm currently sticking with the first one.
For filtering I am using Example.filter(timestamp__date=date). And there's a problem - it seems that __date filters by date converted to UTC. For date 2012-07-27 it returns empty QuerySet and for 2012-07-26 it returns first object.
Is there any way to achieve filtering by timezone aware date?

Related

Django query by separate date and time fields (how to perform conditional order_by)

I have a Meeting model. It has a separate date and time field, the reason why it is not a single datetime field is that the time is allowed to be null.
If I used a single datetime field and set the hours/minutes to 00:00 if no time is given, then I can't distinguish that from a meeting set at 00:00. And some unusual sentinel value like 13:37:42 as no meeting is a weird hack.
Here's the model:
class Meeting(models.Model):
meeting_date = models.DateField(db_index=True)
meeting_time = models.TimeField(db_index=True, null=True, blank=True)
Now the problem comes in to filter by a given date/time.
So I think the solution is to filter by date, then order by the time. E.g. to get the latest meeting that is before now:
from datetime import datetime
now = datetime.now()
prev_meeting = (
Meeting.objects.filter(meeting_date__lte=now.date())
.order_by('-meeting_date', f'meeting_time <= {now.time()}', '-meeting_time')
.first()
)
The f'meeting_time <= {now.time()}' is the part I don't know how to do with the django ORM, but I know how to do with SQL. the Django Docs do not mention conditional ordering.
The solution I came up with is to use a single datetime field to store the date/time, and then instead of a sentinel time value, I have an additional boolean value storing whether the time was set or not. If the time was not set, then then datetime time is 00:00 and the time_was_set field is set to False.

how to pass date time parameter as date in POSTMAN

I'm trying to perform a GET where for a datetime field I shall pass only date and it should provide the necessary results. Below is the URL that I'm trying however it does not work
https://hostname/oslc/os/table?oslc.select=assetnum, location&oslc.where=assetstatus.code="ABC" and siteid="XXXX" and assetstatus.location="204345104" and assetstatus.changedate="2022-06-18"
The change date is stored in the database as 2022-06-18 08:00:01.0 however we would pass only date.

Django ORM converting date to datetime which is slowing down query 30x

I'm attempting query a table and filter the results by date on a datetime field:
.filter(bucket__gte = start_date) where bucket is a datetimefield and start_date is a date object.
However django converts the start_date to a timestamp in the raw sql ex 2020-02-01 00:00:00 when I want it just be a date ex 2020-02-01.
For some reason casting bucket to a date or casting start_time to a timestamp makes the query 30x slower.
When I manually write a query and compare bucket directly to a date ex bucket >= '2020-02-01' the query is blazing fast.
How can I get the django orm to do this?
Seems that its most efficient to convert your date to a datetime in python then do the lookup on the orm since you are filtering on a DateTimeField
from datetime import datetime
.filter(bucket__gte=datetime.combine(start_date, datetime.min.time()))
If the field bucket is indexed, the explain of this query should indicate an Index Scan which would provide desired and most efficient execution plan.
If not it should still be faster since you avoid casting
For some reason casting bucket to a date or casting start_time to a timestamp makes the query 30x slower.
Yes, casting bucket to a date would prevent use of an index (unless the index was over the casted column). But casting start_time to a timestamp would not. What is it 30 times slower than? You just said python automatically converts it, so, how is that different than casting it? As in, what is your actual code?
When I manually write a query and compare bucket directly to a date ex bucket >= '2020-02-01' the query is blazing fast.
OK, but what is it actually doing?
explain select * from foo where bucket > '2021-03-01';
QUERY PLAN
-------------------------------------------------------------------------
Seq Scan on foo (cost=0.00..38.25 rows=753 width=8)
Filter: (bucket > '2021-03-01 00:00:00-05'::timestamp with time zone)
(2 rows)
PostgreSQL is also converting it to a timestamp. Does it give the right answer or the wrong answer?
Try convet your datetime to date in filter:
.filter(bucket__date__gte = start_date)

Group objects by dates

clicks = SellerClick.objects.extra({'date' : "date(timestamp)"}).values('date').annotate(count=Count('timestamp'))
The model has a datetime field called timestamp that was are using. I first, convert the datetime field to just a date field. Then the rest is guessing. I need to group by, and then count how many objects are of each date.
So the desired result would be a date, then a count, based on how many objects have that date in the timestamp field.
I prefer to use annotate over extra
from django.db.models.expressions import RawSQL
SellerClick.objects.annotate(
date=RawSQL('date(date_joined)',[]),
).values('date').annotate(count=Count('date')))
You've got everything but an initial queryset there. The extra sql you're passing doesn't include a select so you need to give it something to act on.
clicks = SellerClick.objects.all()
.extra({'date' : "date(timestamp)"})
.values('date')
.annotate(count=Count('timestamp'))
Ref: StackOverflow: Count number of records by date in Django

how to extract date from a datetime field inside a filter in django

I have used this query in my view..
temp2=transaction.objects.filter(user_id=client_obj,Date_of_trans.date()=rec_var1)[0].Trans_Amount
I need to compare a datetime field present in my model named Date_of_trans to a variable received from user but the code is not working... what query should be written?
This is basically a sql query. So you should think like that. How can you do this in sql. I mean what condition will you apply in sql. For finding records of particular date with datetime field you should check records between start of the day to end of the day.
try this
from datetime import datetime, time
temp2=transaction.objects.filter(user_id=client_obj,Date_of_trans>datetime.combine(rec_var1, time(0,0,0)), Date_of_trans <= datetime.combine(rec_var1, time(23,59,59)) )[0].Trans_Amount
The above code is written taking into consideration that rec_var1 is a date() object.
Here you check all transactions between start of the day, till end of the day. I think this will resolve your problem.
I've use datetime.combine function which combines date and time object to form datetime object which is required here.
Thanks