In my model I want to be able to input duration, like 2 years, 5 months, etc.
In version 1.8 DurationField was introduced so I tried using that:
In my model I have
user_validPeriod = models.DurationField()
Trying to add a new User from my admin panel, If I try typing something like 2d or 2 days in the appearing text-field though I get Enter a valid duration.
Can someone provide me with an example of how this field is supposed to be used?
To use a DurationField in django 1.8 you have to use a python datetime.timedelta instance like this:
Considering this model :
from django.db import models
class MyModel(models.Model):
duration = models.DurationField()
You can set a duration this way :
import datetime
my_model = MyModel()
my_model.duration = datetime.timedelta(days=20, hours=10)
And query it this way :
# Equal
durations = MyModel.objects.filter(duration=datetime.timedelta(*args, **kwargs))
# Greater than or equal
durations = MyModel.objects.filter(duration__gte=datetime.timedelta(*args, **kwargs))
# Less than or equal
durations = MyModel.objects.filter(duration__lte=datetime.timedelta(*args, **kwargs))
More info on datetime.timedelta here and on DurationField here.
In your admin panel, you can enter a duration with a string with following format : [DD] [[hh:]mm:]ss
Related
I want an "active_in" attribute as a timeframe. I assume that the DBMS is optimized for the postgresql tsrange field, and as such it is preferable to utilize the DateTimeRangeField rather than 2 separate fields for start_date and end_date.
Doing this I desire a default value for the field.
active_in = models.DateTimeRangeField(default=timezone.now+'-'+timezone.now+10YEARS)
Is my assumption about the DateTimeRangeField performance true?
Is there a smart solution be it creating a new; function,class or
simply manipulating the 2nd last digit?
My possible solutions:
Code using string manipulation:
active_in = models.DateTimeRangeField(default=timezone.now+'-'+timezone.now[:-2]+'30')
Code using custom function object: (adjusted from here: https://stackoverflow.com/a/27491426/7458018)
def today_years_ahead():
return timezone.now + '-' timezone.now() + timezone.timedelta(years=10)
class MyModel(models.Model):
...
active_in = models.DateTimeRangeField(default=today_years_ahead)
There's no need for string manipulation, as the documented Python type for this field is DateTimeTZRange.
I can't say I've ever used this field before, but something like this should work:
from psycopg2.extras import DateTimeTZRange
from django.utils import timezone
from datetime import timedelta
def next_ten_years():
now = timezone.now()
# use a more accurate version of "10 years" if you need it
return DateTimeTZRange(now, now + timedelta(days=3652))
class MyModel(models.Model):
...
active_in = models.DateTimeRangeField(default=next_ten_years)
I'm developping a web api using django, I have a TimeField that stores hours:minutes:seconds, since it will be compared to a hours:minutes (without seconds) coming from the mobile app, the comparison will always fail.
here is a comparison without seconds which is returnning an empty QuerySet:
>>> journey = Journey \
... .objects \
... .filter((Q(route__departStation=1) | Q(route__stop__station_id=1)),
... (Q(route__arrivalStation=1) | Q(route__stop__station_id=1)),
... route__departDate="2019-07-31", route__departTime="10:57")
>>> journey
<QuerySet []>
and here is when I add seconds to the comparison:
>>> journey = Journey \
... .objects \
... .filter((Q(route__departStation=1) | Q(route__stop__station_id=1)),
... (Q(route__arrivalStation=1) | Q(route__stop__station_id=1)),
route__departDate="2019-07-31", route__departTime="10:57:05")
>>> journey
<QuerySet [<Journey: Journey object (1)>]>
so please, how can I prevent the seconds from being saved to the database from this TimeField(), or at least how can I limit the comparison to hours and minutes only.
You can use a TruncMinute expression [Django-doc] here:
from django.db.models.functions import TruncMinute
journeys = Journey.objects.annotate(
depart_minute=TruncMinute('route__departTime')
).filter(
(Q(route__departStation=1) | Q(route__stop__station_id=1)),
(Q(route__arrivalStation=1) | Q(route__stop__station_id=1))
route__departDate='2019-07-31', depart_minute='10:57'
)
That being said, I suggest you use a DateTimeField over a DateField and TimeField. Time actually only makes sense in combination with a date (and timezone). Many countries have daylight saving time (DST), or have changed their timezone throughout history. Therefore it is better to combine these.
In the model you can basically override the save method, take the timefield attribute and override it with a new datetime.time object, but without storing the seconds in it.
Here is an example:
from django.db import models
from datetime import time
class Route(models.Model):
departTime = models.TimeField(null=True, blank=True)
def save(self, *args, **kwargs):
self.departTime = time(hour=self.departTime.hour, minute=self.departTime.minute)
return super().save(*args, **kwargs)
However, bare in mind, that the save method is not going to be called when you are using bulk operations to create Route objects or update on querysets.
In those cases you can make use of manager classes to override for instance the bulk_create or bulk_update methods or QuerySet to override the update method and only store hours and minutes there.
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 want to send an email to users who haven't activated their accounts every 120 days. I'm using a DateTimeField for their created attribute.
How can I retrieve a queryset of users for whom created % 120 == 0?
Here's what I'm trying, using annotate and F objects:
members = Member.objects.annotate(
days_old=(datetime.datetime.now() - F('created'))
)
members = members.annotate(modulo_days=F('days_old') % 120)
members = members.filter(modulo_days=0)
...but this returns the errors:
TypeError: expected string or buffer
ProgrammingError: operator does not exist: interval % integer
How can I retrieve this queryset looking for the modulo of a timestamp on a Django model?
Another way of doing a queryset that could work for you:
from datetime import timedelta
from datetime import datetime
to_compare_datetime = datetime.now() - timedelta(days=180)
members = Member.objects.filter(account_activated=False, created__year=to_compare_datetime.year, created__month=to_compare_datetime.month, created__day=to_compare_datetime.day)
I'm supposing that your Member model has a field account_activated, and that the created field is a DateTimeField. Hope this can help you :)
In django, I want to get the age (in days) of an instance of a class. I tried doing that by subtracting its creation date field from today, but it does not seem to work properly. date.today() works fine, but DateField is giving me trouble. I looked at its source code and the django docs online for my version but I'm not sure how to manipulate it to perform the subtraction.
import datetime.date
from django.db import models
class MyItem(models.Model):
item_name = models.CharField(max_length = 30)
creation_date = models.DateField()
def age(self):
return date.today() - creation_date
my_first_item = MyItem(item_name = 'First', creation_date = '2005-11-01')
print my_first_item.age.days
Any input would be greatly appreciated!
Your problem is that you are trying to use a field instance outside of a model to represent a value.
models.DateField is a class which represents a database field with a type of "date". I suspect that you are looking to do one of the following:
Just do straight date math
Work with a value returned by a model
In the case of 1, you don't want to use Django's models at all. All you need and want is python's date and time handling classes. For your specific example all you need to use is a pair of date objects and you will end up with a timedelta object.
To do what you were trying to do in your example with the python standard classes, see the example below:
from datetime import date
birthday = date(year=2005, month=11, day=1)
today = date.today()
age = today - birthday
print age.days()
Here we instantiate a date with the birthdate values, we get a date with today's values, subtract them to get a timedelta, and finally print the number of days between the two dates.
In the case of 2, let's look at an example model:
class Person(models.Model):
name = models.CharField(max_length=100)
birthday = models.DateField()
Here we have a model where we've used models.CharField and models.DateField to describe a table in the database which contains a "varchar" column and a "date" column. When we fetch instances of this model using the ORM, Django handles converting whatever value the database returns to a native datatype. Now let's look at some code that figures out the age of an instance of a person:
from datetime import date
from myapp.models import Person
person = Person.objects.get(id=1)
age = date.today() - person.birthday
print age.days
Here you can see that we fetch an instance of the person model from the database and then we subtract their birthday from today. We're able to do this here, because when we access "person.birthday" Django is transforming whatever value the database returned into a python date object. This is the same type as the date object returned by "date.today()" so the "-" operator makes sense. The result of the subtraction operation is a timedelta object.