NDB query by time part of DateTimeProperty - python

I need to query items that where added at some time of day, ignoring which day. I only save the DateTime of when the item was added.
Comparing datetime.Time to DateTimeProperty gives an error, and DateTimeProperty does not have a time() method.

The only way would be to store the time of day as a separate property. An int will be fine, you can store it as seconds. You could do this explicitly (ie set the time property at the same time you set the datetime, or use a computedproperty to automatically set the value.

I've the same problem (more or less) and I think that the only way is build our own date class model.
Something like this:
class Date(ndb.model):
...
day = ndb.IntegerProperty()
month = ndb.IntegerProperty()
year = ndb.IntegerProperty()
...
class Anything(ndb.Model):
...
dateTime = ndb.StructuredProperty(Date)
...
Instead of:
class Anything(ndb.Model):
...
dateTime = ndb.DateTimeProperty()
...
But also I think that we should have other way to do this easier.

Related

Filter Django DB object with a manipulated keyword

I take a timestamp for my Institution class:
class Institution(models.Model):
timestamp_utc = models.DateTimeField()
If there is an entry in the DB that has the same year, month and date (not time), then I want to update the value of the entry. If not, then I want to create a new entry.
The conditional is as follows:
if Institution.objects.filter(timestamp_utc.strftime("%Y/%m/%d")=b['timestamp_utc'].strftime("%Y/%m/%d")).exists():
I am getting this error:
Exception Value: keyword can't be an expression
Is there a way to filter the DB object with a manipulated keyword?
You can just filter by the date range, i.e. time stamps that are great than or equal to the date, and less that the date + 1 day.
from datetime import relativedelta
date_start = b['timestamp_utc'].strftime("%Y-%m-%d")
date_end = (b['timestamp_utc'] + relativedelta(days=1)).strftime("%Y-%m-%d")
if Institution.objects.filter(
timestamp_utc__gte=date_start, timestamp_utc__lt=date_end
).exists():

Find objects with date and time less then 24 hours from now

I have model with two fields:
class Event(models.Model):
date = models.DateField(_(u'Date'))
time = models.TimeField(_(u'Time'))
I need to find all objects where date&time is in 24 hours from now.
I am able to do this when using DateTime field, but I am not sure how to achieve this when fields are separated. Thanks in advance.
For the simple case (not sure if all are simple cases though...), this should do the trick:
import datetime
today = datetime.datetime.now()
tomorrow = today + datetime.timedelta(days=1)
qs_today = queryset.filter(
date=today.date(),
time__gte=today.time(),
)
qs_tomorrow = queryset.filter(
date=tomorrow.date(),
time__lt=tomorrow.time(),
)
qs = qs_today | qs_tomorrow
As you state you can do what you want with a DateTimeField, but now with the separate fields, I understand your issue is how to combine them.
Looking at the docs for DateField - your date variable is a datetime.date instance and similarly for TimeField time is a datetime.time. You can convert these into a datetime.datetime by using combine()
import datetime as dt
datetime = dt.datetime.combine(date,time)
You now have the datetime object as you would have from DateTimeField. You say in the question you can do the 24 hour from now bit from there, although let me know in comments if you need that made explicit.
Caveat I combine will fail where one of the fields is None - you state this can't happen, so I haven't added any error checking or validation of this.
EDIT
It occurs to me that the problem may not be the combination, but adding the calculated field to the Event object. You could look at this Q&A, or this. In summary you define the calculated value in a function in your class and then make it a property - either with a decorator or a function call. There's an example in the docs, adapting for your case:
def _get_datetime(self):
'''Returns a combination of date and time as a datetime'''
return dt.datetime.combine(self.date,self.time)
datetime = property(_get_datetime)
This should behave in the same way as you would expect a DateTimeField to behave.
You can use Q objects to search for "yesterday after current time or today before current time":
from django.db.models import Q
from .models import Event
from datetime import datetime, timedelta
def get_event_during_last_day():
now = datetime.now()
today = now.date()
yesterday = (now - timedelta(day=1)).date()
time = now.time()
query_yesterday = Q(date=yesterday, time__gt=time)
query_today = Q(date=today, time__lt=time)
return Event.objects.filter(query_yesterday | query_today)

Compare saved date field with new unsaved object

I'm triying to update a record if the date is the same.
To do that, I retrieve the last record using:
saved_object = TheModel.objects.latest("date")
new_object = TheModel.objects.create(date="2014-12-15")
And then I compare the dates using:
if saved_object.date == new_object.date:
doStuffWithTheSavedObject()
saved_object.save() # update
else:
new_object.save() # insert new one
Looking at the database, I see that the dates are the same so the if statement is returning false. After debuggin it, I see that the new_object.date is a str and not a date type as I thought it should be.
My question is, how can I prepare the new_object so it has a date field with the right type without saving it into the database and without passing it a casted date manually.
Regards
Update:
class TheModel(models.Model):
date = models.DateField()
a = models.IntegerField()
b = models.IntegerField()
c = models.IntegerField()
Use datetime.date or datetime.datetime (for DateField or DateTimeField accordingly):
import datetime
new_object = TheModel(date=datetime.date(2014, 12, 15))
if you have date as string on input, use strptime
new_object = TheModel(
date=datetime.datetime.strptime('2014-12-15', '%Y-%m-%d'))

allow HH:MM kind of input in a django DateTimeField instead of long format

I have a model like this
class Timer(models.Model):
"""Represents a timing system"""
start_time = models.DateTimeField(default=datetime.datetime.now())
end_time = models.DateTimeField()
and a form that takes this as the model
class JobForm(forms.ModelForm):
class Meta:
exclude = ['slug','author','duration',]
model = Job
Trouble comes in when i want to add some timing info, and by that i mean that i have to enter it in the long format
DD-MM-YYYY HH:MM:SS
the times will be added in real time on the same day as they happen, so the long format looks like a waste of effort, i would rather do it as
HH:MM
i cant use model.TimeField because i will calculate a duration between a start time and the end time, and someone may straddle midnight by timing their sleep or who knows what else.
How would i allow input in HH:MM and have it as datetimefield (eventualy after some effort)? Id like the code to assume the same date as the current date give HH:MM
After looking at the forms documentation, this is what iv decided to do, since i didn't understand #cclerville's suggestion (maybe django is poor?)
here goes:
in my forms.py
class MyDateTimeField(forms.Field):
def to_python(self, value):
# Return an empty list if no input was given.
if not value:
return []
import datetime
today = datetime.date.today()
hhmm = value.split(':')
val= datetime.datetime.combine(datetime.date.today(), datetime.time(int(hhmm[0]),int(hhmm[1])))
return val
and the form itself:
class JobForm(forms.ModelForm):
end_time = MyDateTimeField()

Django query: How to filter objects by todays day, time and after 30 minutes?

I've got a field in models like:
class Sample(models.Model):
start = models.TimeField(verbose_name=_("start time"))
end = models.TimeField(verbose_name=_("end time"))
Now, a need to filter my object by "start" and "end" attributes, e.g, it should filter all objects by todays day, time and time within 30 minutes.
I tried:
models.Sample.objects.filter(start__gt=datetime.now(),
end__lt=datetime.now() + timedelta(minutes=30))
I know, that filtering with two filters is a mistake.. and my code not filtering by today's day. For example, i need to have all objects today on (Tuesday), from 12h till 12:30h
Thanks for help in advance.
You have used used TimeField in your model declaration. That stores only the time with no data for day, month or year.
A time, represented in Python by a datetime.time instance
So instead of using datetime.now() use datetime.now().time() and instead of datetime.now() + timedelta(minutes=30) use (datetime.now() + timedelta(minutes=30)).time()
To be able to include filtering by day, month, year and time replace TimeField in the model with DateTimeField. The filtering using datetime.now() and the timedelta(minutes=30) will work as in your original question.

Categories

Resources