DJANGO avoid repeating date on DateTime calculation - python

I have managed to create a very simple model which allows me to subtract 2 DateTime fields, like so:
class Log(models.Model):
date = models.DateField()
take = models.DateTimeField()
land = models.DateTimeField()
tot = models.CharField(max_length=200, blank=True, default='00000')
def __str__(self):
return str(self.date)
def time_delta(self):
tdelta = self.land - self.take
return str(tdelta)
def save(self, *args, **kwargs):
self.tot = self.time_delta()
super(Log, self).save(*args, **kwargs)
My problem is the user would have to specify the date on every field. How could I make the fields take and land refer to date once and for all?

I don’t know how to do that in your Django model. I think you have to calculate the dates and times in your controller instead, and then register the values in your database.
You can do something like that with datetime.datetime.combine() function:
Return a new datetime object whose date components are equal to the given date object’s, and whose time components are equal to the given time object’s.
You have a reference date, for instance: today.
import datetime
date = datetime.date.today()
The user enter the takeoff time, you can combine this time with the reference date.
takeoff_time = datetime.time(8, 12)
takeoff_datetime = datetime.datetime.combine(date, takeoff_time)
print(takeoff_datetime.isoformat(" "))
# -> 2016-12-21 08:12:00
If the landing date is the same as the takeoff date, you can calculate the landing date/time with the same date reference:
landing_time = datetime.time(12, 37)
landing_datetime = datetime.datetime.combine(date, landing_time)
print(landing_datetime.isoformat(" "))
# -> 2016-12-21 12:37:00
Then, you can register the date, _takeoff_datetime_ and _landing_datetime_ in your database.
Note: you can do the same with the flight duration

I eventually managed to find a solution largely based on Laurent's answer so here it is,if that can ever help someone else:
from datetime import datetime
def calculation(self):
calc_take_off = datetime.combine(self.date, self.take)
calc_land = datetime.combine(self.date, self.land)
result = calc_land - calc_take_off
return str(result)
and then to save this in models:
def save(self, *args, **kwargs):
self.tot = self.calculation()
super(Log, self).save(*args, **kwargs)

Related

How to filter through date in django-views?(Doesn't show the expired one)

models.py
class Dibbs_Fields(models.Model):
hash = models.CharField(max_length=16)
nsn = models.CharField(max_length=32)
nomenclature = models.TextField()
technical_documents = models.TextField()
return_by = models.DateField()
How to filter this class in django views according to the date return_by ? I don't want to show the data that is expired i.e. if the return_by date is earlier than today's date, then it should not show.
You can do this:
from datetime import date
def func(request):
today = date.today()
data = Dibbs_Fields.objects.filter(
return_by__lt=today)
The code simply returns data are earlier than today's date.
EDIT
return_by__lt # less than
return_by__gt # greater than
return_by__gte # greater than or equal to
return_by__lte # less than or equal to

add time when we save a Timefield in django

I have a dateTime field in a model. The dateTime field named breakfast_start_time takes an input.
I have to save another variable or timefield(whichever is better) named breakfast_attendence_start_time whose value should be automatically saved 15 minutes less than the breakfast_start_time.
For this we use
def save(self, *args, **kwargs):
#do something
super().save(*args, *kwargs)
I am trying to do
breakfast_attendence_start_time = breakfast_start_time - time(15,0)
but it is giving error that
class TimeField does not define '_sub_', so the '-' operator cannot be used on its instances
Edited:
Here is the full code
class Hostel(models.Model):
name = models.CharField(max_length=15)
breakfast_start_time = models.TimeField()
lunch_start_time = models.TimeField()
snacks_start_time = models.TimeField()
dinner_start_time = models.TimeField()
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
I am taking start time from admin panel and I want to add 4 more variable/field like breakfast_attendence_start_time whose value should be saved automatically 15 minutes earlier than breakfast_start_time how can I achive that.
You should use timedelta to sub specific time with DateTime field. Such as
import datetime
time_before_15_minute = datetime.datetime.now() - datetime.timedelta(minutes=15)
Use DateTimeField instead of TimeField and use timedelta to make substractions
from datetime import datetime, timedelta
n = datetime(2019, 10, 4, 12, 30)
m = n - timedelta(minutes = 15) # m is now datetime(2019, 10, 4, 12, 15)
You can play with the DateTimeField but this will return time of when this function was called or used. Hope it helps
from django.utils import timezone
class AKA(models.Model):
create_time = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.create_time

how to get year from datefield at django?

i want to get year from birthday.
so i use self.birthday.year
but it make error.
how do i fix it?
best regards.
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_("Name of User"), blank=True, max_length=255) #이름
gender = models.CharField(max_length=1, choices=CHOICES_GENDER) # 성
birthday = models.DateField(null=True) #생일
def calculate_age(self):
import datetime
return int((datetime.date.year - self.birthday.year) +1)
age = property(calculate_age) #나이
Try this solution,
from datetime import date
class User(AbstractUser):
name = models.CharField(_("Name of User"), blank=True, max_length=255)
gender = models.CharField(max_length=1, choices=CHOICES_GENDER)
birthday = models.DateField(null=True)
#property
def calculate_age(self):
if self.birthday:
today = date.today()
return today.year - self.birthday.year - ((today.month, today.day) < (self.birthday.month, self.birthday.day))
return 0 # when "self.birthday" is "NULL"
The problem is that datetime.date.year does not exists. You can fetch the year of a date (or datetime) object with .year, and you can thus for example use today() or now().
Semantically the function is incorrect as well. If I am born in 1984, then I am not per se 35 years old: that depends on whether the current year is before or after the day of birth (for example February 9th).
Finally there can be an error if the self.birthday value is None. In that case you probably want to return None as well.
So a potential solution for this is:
from datetime import date
class User(AbstractUser):
# ...
def calculate_age(self):
bd = self.birthday
if bd:
td = date.today()
return td.year - bd.year - ((td.month, td.day) < (bd.month, bd.day))
We thus first calculate today(), and then we return the current year minus the year of the birthday and minus one if today is still before the birthday this year.
In case the user did not specify his/her birthday, then the calculate_age(..) will return None (a value that can be interpreted as "unknown").
An issue that still remains (and is harder to fix) are timezones: since today in Australia is another today than in the United States, it is possible that - depending on where the server and users are located - the age of a user is one too high the day before his/her birthday, or one too low one day on his/her birthday. This is a harder problem to solve, since we have no information here where the user is located.

django - date filter without bloat

I need to perform a filter by date with a form where if one of the date parameters is suppressed the upper/lower border of the date range is not being set in filter (which means min possible date/max possible date, respectively)
My code is:
#forms.py
...
start_date = forms.DateField(
required=False,
)
end_date = forms.DateField(
required=False
)
...
# views.py
def get(self, *args, **kwargs):
form = self.request.GET
if form.is_valid():
cd = form.cleaned_data
if not cd['start_date']:
start_date = datetime.date(1,1,1)
else:
start_date = cd['start_date']
if not cd['end_date']:
end_date = datetime.date(3000,1,1)
else:
start_date = cd['end_date']
MyC.objects.filter(date__range=(start_date,end_date))
This code works but looks very cludgy to me (Many senseless if clauses, duplicate code, etc).
Maybe there is a Filter function for this case (if start date is None -> don't filter)?
You can apply the filters as needed. The query won't happen until you use the queryset.
objects = MyC.objects.all()
if cd['start_date']:
objects = objects.filter(date__gt=cd['start_date'])
if cd['end_date']:
objects = objects.filter(date__lt=cd['end_date'])
return objects
if you need default dates you can do:
start_date = self.cleaned_data.get('start_date', datetime.date(1,1,1))
end_date = self.cleaned_data.get('end_date', datetime.date(3000,1,1))
MyC.objects.filter(date__range=(start_date, end_date))

Disable django form field for a given time

I want to disable django fields for 6 months after the date of update. I have saved update_time to a table.
updated_time = a.update_time
disabled_time = a.update_time + timedelta(180)
I want to diable field that updated:
self.fields['first_name'].widget.attrs['readonly'] = True
How can I disable self.fields['first_name'].widget.attrs['readonly'] = True for disabled_time?
Thanks in advance
You can compare, and substract basic datetime objects and make some check at form initialization time:
from datetime import timedelta, datetime
...
class FooForm(ModelForm):
def __init__(self, *args, **kwargs):
super(FooForm, self).__init__(*args, **kwargs)
# check if we already have a saved object and it's not older than 180 days
if self.instance.pk and
(datetime.now() - self.instance.update_time) < timedelta(180):
self.fields['first_name'].widget.attrs['readonly'] = True
class Meta:
model = Foo
(Not really tested but should work as it is.)
Also note, that it is often convenient to keep update_time with auto_now set to True.

Categories

Resources