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
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.
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.
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')
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
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)