Lookup hour on DateTimeField Django - django

I have the model
class Item(models.Model):
inicio = models.DateTimeField()
When I try to make this query:
itens = Item.objects.filter(inicio__hour__gte=6)
It returns me:
FieldError Unsupported lookup 'hour' for DateTimeField or join on the field not permitted.
How can I make this query?

Heads up, this should work as of Django 1.9
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)

You need to filter using a timedelta:
from datetime import datetime, timedelta
five_hours_ago = datetime.now() - timedelta(hours=5)
items = Item.objects.filter(inicio__lt=five_hours_ago)
You can always specify an exact datetime and then subtract 5 hours from it if you don't want 5 hours from the current datetime.
To the best of my knowledge, and according to the documentation, you can only do an exact lookup on an hour, minute or second.

Related

check if today is due date django

I have a model like this
class Tasks(models.Model):
title = models.CharField(max_length=100,null=True,blank=True)
due_date_time= models.DateTimeField(default=timezone.now)
As due date is a date and time field, how I can check if today is due date of this task , while I am saving time and date both
You can make use of the __date lookup [Django-doc]:
from django.utils.timezone import now
Tasks.objects.filter(
due_date_time__date=now().date()
)
or if you work with timezones, you can work with a range check:
from datetime import timedelta
from django.utils.timezone import now
today = now().replace(hour=0, minute=0, second=0, microsecond=0)
tomorrow = today + timedelta(days=1)
Tasks.objects.filter(
due_date_time__gte=today,
due_date_time__lt=tomorrow
)
Note: normally a Django model is given a singular name, so Task instead of Tasks.

Django model elapsed time between two DateTimeFields

I am pretty new to django and haven't been able to find a way to get the elapsed time between two DateTimeFields and save it to another model.
from django.db import models
class Timesheet(models.Model):
startTime = models.DateTimeField(auto_now_add=True)
endTime = models.DateTimeField(blank=True, null=True)
duration = models.DateTimeField(endTime - startTime)
def _str_(self):
return self.startTime
How can I make duration = endTime - startTime?
I am also using a PostgreSQL database.
I wouldn't use a dedicated model field for the duration.
I would use a property on the model instead for the same functionality.
Something like:
#property
def duration(self)
return self.end_time - self.startime
Lucas has a good idea of using an annotation, but if you have a Timesheet instance somewhere that didn't come from that object manager and was not previously annotated, you would have to do a separate database hit to actually annotate it.
This property is used as such:
some_timesheet_instance.duration
Use annotate() to compute the duration field at query time for each object in the queryset
from django.db.models import F, ExpressionWrapper, fields
timesheets = Timesheet.objects.annotate(
duration=ExpressionWrapper(
F('endTime') - F('startTime'),
output_field=fields.DurationField()
)
)
timesheets[0].duration # datetime.timedelta(0, 722, 18373)
Is possible perform another queryset methods over annotations like filter(), order_by(), aggregate(), etc.
timesheets.order_by('-duration')
timesheets.aggregate(Avg('duration')) # {'duration__avg': datetime.timedelta(0, 26473, 292625)}
duration = timesheet.end_time - timesheet.start_time
When you substract two datetime instances you don't get another datetime instance but a timedelta instace, which is just the days, seconds and microseconds difference between the two datetimes. You can't store a timedelta in a DateTimefield, but you can use an IntegerField, for example:
days_in_seconds = duration.days * 86400 # days difference by seconds in a day
duration_in_seconds = duration.seconds + days_in_seconds # duration in seconds
When you want to access the duration as timedelta you just do:
import datetime
duration = datetime.timedelta(seconds=timesheet.duration)
You can also store it as FloatField as suggested in this question.

Django: Combine a date and time field and filter

I have a django model that has a date field and a separate time field. I am trying to use a filter to find a value on the latest record by date/time that is less than the current record's date time.
How do I use annotate/aggregate to combine the date and time fields into one and then do a filter on it?
models.py
class Note(models.model):
note_date = models.DateField(null=True)
note_time = models.TimeField(null=True)
note_value = models.PositiveIntegerField(null=True)
def get_last(n):
"""
n: Note
return: Return the note_value of the most recent Note prior to given Note.
"""
latest = Note.objects.filter(
note_date__lte=n.note_date
).order_by(
'-note_date', '-note_time'
).first()
return latest.note_value if latest else return 0
This will return any notes from a previous date, but if I have a two notes on the same date, one at 3pm and one at 1pm, and I send the 3pm note to the function, I want to get the value of the 1pm note. Is there a way to annotate the two fields into one for comparison, or do I have to perform a raw SQL query? Is there a way to convert the date and time component into one, similar to how you could use Concat for strings?
Note.objects.annotate(
my_dt=Concat('note_date', 'note_time')
).filter(
my_dt__lt=Concat(models.F('note_date'), models.F('note_time')
).first()
I am too late but here is what I did
from django.db.models import DateTimeField, ExpressionWrapper, F
notes = Note.objects.annotate(my_dt=ExpressionWrapper(F('note_date') + F('note_time'), output_field=DateTimeField()))
Now we have added a new field my_dt of datetime type and can add a filter further to do operations
Found an answer using models.Q here: filter combined date and time in django
Note.objects.filter(
models.Q(note_date__lt=n.note_date) | models.Q(
note_date=n.note_date,
note_time__lt=n.note_time
)
).first()
I guess I just wasn't searching by the right criteria.
Here is another Approach which is more authentic
from django.db.models import Value, DateTimeField
from django.db.models.functions import Cast, Concat
notes = Note.objects.annotate(my_dt=Cast(
Concat('note_date', Value(" "), 'note_time', output_field=DateTimeField()),
output_field=DateTimeField()
).filter(my_dt__lte=datetime.now())
Here is another solution following others.
def get_queryset(self):
from django.db import models
datetime_wrapper = models.ExpressionWrapper(models.F('note_date') + models.F('note_time'), output_field=models.DateTimeField())
return Note.objects.annotate(
note_datetime=datetime_wrapper
).filter(note_datetime__gt=timezone.now()).order_by('note_datetime')

How to create a datetime aware for Django in UTC

I have configured my timezone in settings, as America/Guatemala and I have some datetime fields in my models, I'm using default=timezone.now but it is not saving my local hour, which is UTC-6:00, is saving it as UTC-00:00. I can't change that because now there is some important data stored in the database in that way.
I have problems retrieving the data in a queryset, I send a string in request.POST like this:
date='1/09/2016'
And I have tried this to configure my date for the query:
f=date.split('/')
if len(f)>1:
initialdate=datetime.datetime(int(f[2]),int(f[1]),int(f[0]),0,0,0,tzinfo=pytz.UTC)
finaldate=datetime.datetime(int(f[2]),int(f[1]),int(f[0]),23,59,59,tzinfo=pytz.UTC)
And this is my queryset:
sale=Sale.objects.filter(Q(pk=int(cod))|Q(sale_date__range=(initialdate,finaldate)))
But because of the 6 hours of difference between my saved data and my local date and time, if I store a Sale at 6:01pm of my local time, the saved data is stored as 00:01am of tomorrow. If i want to check all the sales that I made today, it doesn't show me the sales after 6pm, because they are saved in a different date.
I have another queries where I send two differents dates, and I use the same code, I just add time 0,0,0 to the first date, and 23,59,59 to the second date, but I have the same problem.
My question is, how can I add those six hours to the dates that I use as parameters? I need the datetime to be aware, and I can't change nothing in my model, I can change only the parameters that I'm sending to the queryset.
I am also have the question. and what I am did is that:
the whole day's date range is: 00:00:00 - 23:59:59, and this is the local datetime, but the datetime in datebase has beed transformed to utc, so I just sub the local datetime 6 hour, and you can do soï¼›
import datetime
f=date.split('/')
if len(f)>1:
initialdate=datetime.datetime(int(f[2]),int(f[1]),int(f[0]),0,0,0,tzinfo=pytz.UTC)
finaldate=datetime.datetime(int(f[2]),int(f[1]),int(f[0]),23,59,59,tzinfo=pytz.UTC)
initialdate = initialdate - datetime.timedelta(hours=6)
finaldate = finaldate - datetime.timedelta(hours=6)
import pytz
from django.utils import timezone
initialdate = datetime.datetime.combine(date, datetime.time.min.replace(tzinfo=timezone.UTC())).astimezone(pytz.timezone('America/Guatemala'))
finaldate = datetime.datetime.combine(date, datetime.time.max.replace(tzinfo=timezone.UTC())))).astimezone(pytz.timezone('America/Guatemala'))
Edited to make date aware
To simply change the date six hours back you can use datetime's timedelta.
To change sale_date of objects within your query you simply need to do this:
import datetime
import pytz
for s in sale:
sale_date = sale_date - datetime.timedelta(hours=6)
sale_date = sale_date.replace(tzinfo=pytz.timezone("America/Guatemala"))
s.save()
To change sale_date of all Sale objects:
import datetime
import pytz
all_sales = Sale.objects.all()
for sale in all_sales:
sale_date = sale_date - datetime.timedelta(hours=6)
sale_date = sale_date.replace(tzinfo=pytz.timezone("America/Guatemala"))
sale.save()
Also, to parse strings containing time information use strptime:
import datetime
date='1/09/2016'
parsed_date = datetime.datetime.strptime(date, '%w/%m%Y')
More info on it here

Django query datetime by adding 5 hours 30 minutes to the original column

I'm trying to write a Django query for orders that when added 5 hours 30 minutes satisfy the condition,created_at is datetime
SELECT id, created_at + time '5:30' as created_at , date(created_at + time '5:30') as created_date
FROM orders WHERE date(created_at + time '5:30') > today_date
How to convert this into Django ORM ?
I assume that TIME_ZONE in setting is set to 'Asia/Kolkata' (i.e. UTC+5:30). If you have this setting, you can use django's timezone module.
Let's say the model name in 'Order'. The above query will be like this in ORM form:
from django.utils import timezone
orders = Order.objects.filter(created_at__gt=timezone.now().date())
And to convert the date got from this query into your timezone:
order = orders.first()
created_at = timezone.localtime(order.created)