Here I am writing property method to display the remaining leave days and total leave days.The total leave days are working fine but def leave_remaining_days(self) this is not working.
I go this error
'datetime.date' object has no attribute 'days'
Here the problem is while returning the no.of days return leave_remaining.days but when i return return leave_remaining just then it works.
How can I calculate the remaining leave days here ?
Only if leave.is_accepted True then i want to calculate remaining days.
I want to decrease days 1 to the end_day by each day until
datetime.date.today() == self.end_day.
EDIT: For this I used celery but this is also not working.Initially to check whether it works or not I set minutes=1 in the periodic task but it doesn't works.
models.py
class Leave(models.Model):
staff = models.ForeignKey(get_user_model(),on_delete=models.CASCADE,related_name='staff')
sub = models.CharField(max_length=300)
msg = models.TextField()
start_day = models.DateField()
end_day = models.DateField()
is_accepted = models.BooleanField(default=False)
is_rejected = models.BooleanField(default=False)
#property
def leave_days(self):
diff = self.end_day - self.start_day
return diff.days
#property
def leave_remaining_days(self):
if self.is_accepted and not datetime.date.today() > self.end_day:
leave_remaining = self.end_day - datetime.timedelta(days=1)
return leave_remaining.days
#changes
from celery.schedules import crontab
from celery.task import periodic_task
#property
#periodic_task(run_every=crontab(minute=1))
def leave_remaining_day(self):
if self.is_accepted and not datetime.date.today() > self.end_day:
leave_remaining = self.leave_days - 1
return leave_remaining
The reason you get this error is because subtracting a timedelta from a date results in a date.
A date has no days attribute (which you can check by creating one and calling dir(...) on it or checking the documentation).
On a sidenote, if you want leave_remaining_days to return how many days are left until the Leave is up, then you should do something like:
#property
def leave_remaining_days(self):
if self.is_accepted and not datetime.date.today() > self.end_day:
delta = self.end_day - datetime.date.today()
return delta.days
Since you are storing the start_day and end_day I'm not sure you need to decrease anything each day. You could perhaps check the property I've written above.
If I understand your question correctly, then in your code:
leave_remaining = self.end_day - datetime.timedelta(days=1)
return leave_remaining.days
leave_remaining is a datetime.date that is 1 day prior to self.end_day, which I think is what you want; just return the date directly like this:
return leave_remaining
I think most obvious answer would be to define your leave_remaining_days prop like this:
#property
def leave_remaining_days(self):
if self.is_accepted:
return self.leave_days - 1
isn't it?
Do you mean this?
#property
def leave_remaining_days(self):
if self.is_accepted and not datetime.date.today() > self.end_day:
leave_remaining = self.end_day - datetime.date.today()
return leave_remaining.days
This shall work:
def leave_remaining_days(self):
if self.is_accepted and not datetime.date.today() > self.end_day:
leave_remaining = self.end_day - datetime.timedelta(days=1)
return leave_remaining.day
leave_remaining.day will give you the remaining leave days
Related
I have the following class in a file called 'GPS_Date.py':
import datetime
from math import floor
class GPS_Date(datetime.datetime):
ref_date = datetime.datetime(1980, 1, 6)
def __init__(self, year, month, day, hour=0, minute=0, second=0):
datetime.datetime.__init__(year, month, day, hour, minute, second)
def gps_week(self):
difftime = self-self.ref_date
return floor(difftime.days / 7)
def day_of_week(self):
difftime = self-self.ref_date
return difftime.days % 7
def day_of_year(self):
return self.timetuple().tm_yday
#staticmethod
def to_GPS_date(date):
return GPS_Date(date.year, date.month, date.day, date.hour, date.minute, date.second)
#staticmethod
def now():
return GPS_Date.to_GPS_date(datetime.datetime.utcnow())
When I run the following code in python3.6 I get the correct solution:
import datetime
from GPS_Date import GPS_Date
time_string = '2019-01-01 23:59:30.0'
date_format = '%Y-%m-%d %H:%M:%S.%f'
time_1 = datetime.datetime.strptime(time_string, date_format)
time_2 = GPS_Date.to_GPS_date(time_1)
add_time = time_2 + datetime.timedelta(minutes=30)
But when I run it with python3.9 I get the following error:
add_time = time_2 + datetime.timedelta(minutes=30)
TypeError: __init__() takes from 4 to 7 positional arguments but 9 were given
I assume something has been changed between python3.6 and python3.9. I've looked at documentation but haven't found anything. Can anyone enlighten me?
datetime.datetime does have more arguments that can be passed than GPS_Date accounts for (i.e. tzinfo and fold). Why this doesn't blow up in Python3.6, I am not sure. But you don't need to override __init__ at all, since you aren't doing anything:
class GPS_Date(datetime.datetime):
ref_date = datetime.datetime(1980, 1, 6)
def gps_week(self):
difftime = self - self.ref_date
return floor(difftime.days / 7)
def day_of_week(self):
difftime = self - self.ref_date
return difftime.days % 7
def day_of_year(self):
return self.timetuple().tm_yday
#staticmethod
def to_GPS_date(date):
return GPS_Date(date.year, date.month, date.day, date.hour, date.minute, date.second)
#staticmethod
def now():
return GPS_Date.to_GPS_date(datetime.datetime.utcnow())
is perfectly fine. (Also note: If you were to do something, you need to override __new__ instead of __init__)
I am trying to expire tokens after its creation with a max duration of 1 minute to meet security requirements. my function looks like this, but I don't think is doing it the right way, and I Would like to know what is the best way to expire the token after 1 minute? I am using the technique of diffing two times. the following function works under models.py
def is_token_expired(self):
if self.token == None:
return False
now = datetime.datetime.utcnow().replace(tzinfo=utc)
timediff = now - self.created_at
if timediff.seconds / 60 - 1 > 0:
return True
return False
I think the elegant way to archive your goal is leveraging django cache.
Sample code:
class Foo(models.Model):
...
def save(self, *args, **kwargs):
if not self.pk:
# save the token when record created
cache.set('token_key', '<Your token>', timeout=60)
super(Foo, self).save(*args, **kwargs)
#property
def is_token_expired(self):
# check if the token expired
return cache.get('token_key') is None
#property
def token(self):
# get token
return cache.get('token_key')
It is better to use #property in your model:
from datetime import timedelta
class Foo(models.Model):
some_field = models.CharField()
creation_date = models.DateTimeField(auto_now_add=True)
#property
def is_expired(self):
if datetime.now > (self.creation_date + timedelta(minutes=1)):
return True
return False
you can change timedelta(minutes=1) to amount that your token is valid.
and use it in your code like this:
if your_instance.is_expired == True:
# do something
You can also use Django builtin cache system (that Enix mentioned) as a better approach.
I have validate the start_date and end_date. I need to set null end date field while raising the error. Here is my code:
#api.onchange('end_date')
def onchange_end_date(self, end_date, start_date):
if (start_date and end_date) and (start_date < end_date):
raise exceptions.except_orm(_('Warning!'),_('The start date must be less than to the end date.'))
In Odoo on-change method you no need to pass any parameter, system will directly get it from self object.
#api.onchange('end_date')
def onchange_end_date(self):
if (self.start_date and self.end_date) and (self.start_date < self.end_date):
raise exceptions.except_orm(_('Warning!'),_('The start date must be less than to the end date.'))
This may help you.
Hello you can try this i hope it helps you
import ValidationError
#api.onchange('end_date')
def onchange_end_date(self):
if (self.start_date and self.end_date) and (self.start_date < self.end_date):
raise ValidationError(''The start date must be less than to the end date.'))
Thanks
Other than onchange we can use constraints... It helps to validate something when create and edit and also in change..
Here is my code and it works fine
#api.multi
#api.constrains('start_date', 'start_date')
def _check_date(self):
start_date = self.start_date
end_date = self.end_date
if (start_date and end_date) and (start_date > end_date):
raise ValidationError(_('The start date must be less than to the end date. '))
Thank You
I have a model like this;
starttime = models.TimeField('Show Start Time', )
duration = models.DurationField('Duration',)
endtime = models.TimeField('Show End Time (Optional)',blank=True, null=True )
with the starttime and duration I am trying to arrive the endtime while storing the object;
def save(self, *args, **kwargs):
startdelta=timedelta(hours=self.starttime.hour,minutes=self.starttime.minute,seconds=self.starttime.second)
enddelta = startdelta + self.duration
self.endtime = enddelta
super(Showsets, self).save(*args, **kwargs)
Above code throws me error, I want to know how the timefield and duration field works in django also please assist with the ways to query the fields based on starttime or endtime (like objects that starts (starttime) in 30mins from now).
Also curious to know if there are any django-app(add-ons) for time based querying.
Thanks a ton!
Not sure if this will be a good solution for your circumstance but I normally do something like:
start_time = models.TimeField()
end_time = models.TimeField()
def duration(self):
return self.end_time - self.start_time
It seems like a much more concise solution than storing start time with duration and then calculating the end_time on save().
You can combine starttime with today's date and add duration:
from datetime import datetime, date
self.endtime = (datetime.combine(date.today(), self.starttime) + self.duration).time()
How do I set the timezone of a datetime instance that just came out of the datastore?
When it first comes out it is in UTC. I want to change it to EST.
I'm trying, for example:
class Book( db.Model ):
creationTime = db.DateTimeProperty()
When a Book is retrieved, I want to set its tzinfo immediately:
book.creationTime.tzinfo = EST
Where I use this example for my EST object
However I get:
attribute 'tzinfo' of 'datetime.datetime' objects is not writable
I've seen a number of answers that recommend pytz and python-dateutil, but I really want an answer to this question.
datetime's objects are immutable, so you never change any of their attributes -- you make a new object with some attributes the same, and some different, and assign it to whatever you need to assign it to.
I.e., in your case, instead of
book.creationTime.tzinfo = EST
you have to code
book.creationTime = book.creationTime.replace(tzinfo=EST)
If you're receiving a datetime that's in EST, but doesn't have its tzinfo field set, use dt.replace(tzinfo=tz) to assign a tzinfo without modifying the time. (Your database should be doing this for you.)
If you're receiving a datetime that's in UDT, and you want it in EST, then you need astimezone. http://docs.python.org/library/datetime.html#datetime.datetime.astimezone
In the vast majority of cases, your database should be storing and returning data in UDT, and you shouldn't need to use replace (except possibly to assign a UDT tzinfo).
What you want is right there in the docs.
from datetime import tzinfo, timedelta, datetime
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
DSTSTART = datetime(1, 4, 1, 2)
DSTEND = datetime(1, 10, 25, 1)
def first_sunday_on_or_after(dt):
days_to_go = 6 - dt.weekday()
if days_to_go:
dt += timedelta(days_to_go)
return dt
class USTimeZone(tzinfo):
def __init__(self, hours, reprname, stdname, dstname):
self.stdoffset = timedelta(hours=hours)
self.reprname = reprname
self.stdname = stdname
self.dstname = dstname
def __repr__(self):
return self.reprname
def tzname(self, dt):
if self.dst(dt):
return self.dstname
else:
return self.stdname
def utcoffset(self, dt):
return self.stdoffset + self.dst(dt)
def dst(self, dt):
if dt is None or dt.tzinfo is None:
# An exception may be sensible here, in one or both cases.
# It depends on how you want to treat them. The default
# fromutc() implementation (called by the default astimezone()
# implementation) passes a datetime with dt.tzinfo is self.
return ZERO
assert dt.tzinfo is self
# Find first Sunday in April & the last in October.
start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
if start <= dt.replace(tzinfo=None) < end:
return HOUR
else:
return ZERO
now = datetime.now()
print now
print now.tzinfo
Eastern = USTimeZone(-5, 'Eastern', 'EST', 'EDT')
now_tz_aware = now.replace(tzinfo=Eastern)
print now_tz_aware
output:
2010-01-18 17:08:02.741482
None
2010-01-18 17:08:02.741482-05:00