How to arrive endtime using starttime and duration in django model - python

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()

Related

Is there a way to overload len() so that I don't have to use an int?

I am creating a class that works with time ranges,
class Time_Range:
"""A class that models time ranges."""
def __init__(self, start:str, end:str, time_format='%m/%d/%Y %H:%M'):
"""Creates a time range.
Parameters:
start : str - start time.
end : str - end time.
"""
start_time = datetime.strptime(start, time_format)
end_time = datetime.strptime(end, time_format)
if start_time > end_time:
raise ValueError("End time is before start time.")
self.start = start_time
self.end = end_time
def __len__(self):
"""Returns the elapsed time in the time range."""
return self.end - self.start
I defined len() to be the time elapsed as a timedelta object, but im getting an error
"TypeError: 'datetime.timedelta' object cannot be interpreted as an integer"
In my opinion, this is a perfectly reasonable way to implement len() in this class, but Python won't allow it. Is there a better way to do this? Do I have to resort to writing my own length method?
It seems you are trying to fit something that isn't into a class.
If your class has only two methods, one of which is __init__, then (in general) it should be a function instead:
def time_range(start:str, end:str, time_format='%m/%d/%Y %H:%M'):
start_time = datetime.strptime(start, time_format)
end_time = datetime.strptime(end, time_format)
if start_time > end_time:
raise ValueError("End time is before start time.")
return end_time - start_time
Especially since you are producing a TimeDelta anyway.

Update a row in a Django data base based on a column value

I am new to Django and specifically Models and have been struggling to understand how to update data in the data base.
Models.py:
# Create your models here.
class logTimes(models.Model):
fast_finshed = models.BooleanField(default=False)
start_date_time = models.DateTimeField('start fast')
end_date_time = models.DateTimeField('end fast')
In my View, I have a function to add a row of data when submitting one of two forms that will either add a new row of data or update an existing row of data. I cannot figure out how to make the update I have tried too many things to write here. I have been reviewing the Django docs and not making progress at all.
Views.py:
#function to add a fast to the data base or update the last fast with an end date and time
def start_or_end_fast(request):
#If starting fast, update the data base with fast_finished = False
#A new fast start date and time using current date and time
#A specific end date and time set in the future
if request.method == 'POST' and 'start_fast' in request.POST:
l = logTimes(fast_finshed=False,start_date_time=datetime.now(),end_date_time=datetime(year=2023, month=1, day=1, hour=12, minute=00, second=00))
l.save()
print('fast started')
return render(request,'startandstoptimes/index.html')
#If ending a fast, find the last fast that has the specific end date and time
#And update end_date_time to the current date and time
elif request.method == 'POST' and 'end_fast' in request.POST:
#Update row where end_date_time = year=2023, month=1, day=1, hour=12, minute=00, second=00
#Change to current date and time
???????
print('Fast ended')
return render(request,'startandstoptimes/index.html')
#If Just refreshing the page
else:
return render(request,'startandstoptimes/index.html')
Any advice would be much appreciated, I find this a bit difficult to wrap my head around coming from using SQL.
Thank you!
#function to add a fast to the data base or update the last fast with an end date and time
def start_or_end_fast(request):
#If starting fast, update the data base with fast_finished = False
#A new fast start date and time using current date and time
#A specific end date and time set in the future
if request.method == 'POST' and 'start_fast' in request.POST:
l = logTimes(fast_finshed=False,start_date_time=datetime.now(),end_date_time=datetime(year=2023, month=1, day=1, hour=12, minute=00, second=00))
l.save()
print('fast started')
return render(request,'startandstoptimes/index.html')
#If ending a fast, find the last fast that has the specific end date and time
#And update end_date_time to the current date and time
elif request.method == 'POST' and 'end_fast' in request.POST:
#Update row where end_date_time = year=2023, month=1, day=1, hour=12, minute=00, second=00
#Change to current date and time
logTimes.objects.filter(
# this will be the WHERE part of the SQL query
end_date_time=datetime(year=2023, month=1, day=1, hour=12, minute=0, second=0)
).update(
# this will be the SET XXX VALUES XXX part of the query
end_date_time=datetime.now()
)
print('Fast ended')
return render(request,'startandstoptimes/index.html')
#If Just refreshing the page
else:
return render(request,'startandstoptimes/index.html')

What parameters to use in this function?

I am trying to put this piece of code into a function so that i can avoid just copy pasting the code everytime. Here the code that I want to put in a function:
f= open("test.txt","w+")
os.chdir("//10.2.30.61/c$\Qlikview_Tropal/apps/ventes")
for fichiers in glob.glob("*"):
today = datetime.datetime.today()
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(fichiers))
duration = today - modified_date
if duration.days < 1:
f.write(f"{fichiers} = {duration} \n")
edit1: I have changed my code like Chepner's advice now the issue still remains that there is no output being written to my test.txt file.
What am I missing ?
Thanks alot!
As is, you don't need any parameters (though I'm going to re-write it slightly to use a with statement):
def my_function():
with open("test.txt", "w+") as f:
os.chdir("//10.2.30.61/c$\Qlikview_Tropal/apps/ventes")
for fichiers in glob.glob("*"):
today = datetime.datetime.today()
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(fichiers))
duration = today - modified_date
if duration.days < 1:
f.write(f"{fichiers} = {duration} \n")
my_function()
You might want to parameterize the function in several ways, however. Both the hard-coded output file name and the input directory are candidates.
def my_function(output_name, input_dir):
with open(output_name, "w+") as f:
os.chdir(input_dir)
for fichiers in glob.glob("*"):
today = datetime.datetime.today()
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(fichiers))
duration = today - modified_date
if duration.days < 1:
f.write(f"{fichiers} = {duration} \n")
my_function("test.txt", "//10.2.30.61/c$\Qlikview_Tropal/apps/ventes")
There's no one answer to this question. It depends on how you want to reuse this function. You can start by asking yourself these questions:
Will I always have to open the same file i.e. test.txt or if it not, you can set it as an argument.
Will I always change directory to the same folder i.e. "//10.2.30.61/c$\Qlikview_Tropal/apps/ventes"
Will I always write the same text to files i.e {fichiers} = {duration} \n
If these things change in different context, you can make them arguments. But, if everything will be the same, you can just define a function without any arguments.
If you just want to have a function without any parameter you can do like:
def my_function():
f= open("test.txt","w+")
os.chdir("//10.2.30.61/c$\Qlikview_Tropal/apps/ventes")
for fichiers in glob.glob("*"):
today = datetime.datetime.today()
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(fichiers))
duration = today - modified_date
if duration.days < 1:
f.write(f"{fichiers} = {duration} \n")
Call it simply like: my_function()
Function with parameters: Based on the code you have provided, you can keep file name and url as parameters to the function like:
Functions with parameters can be used again and again with different parameters
def my_function(fileName, URL):
f= open(fileName,"w+")
os.chdir(URL)
for fichiers in glob.glob("*"):
today = datetime.datetime.today()
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(fichiers))
duration = today - modified_date
if duration.days < 1:
f.write(f"{fichiers} = {duration} \n")
Then call it like:
my_function("test.txt", "//10.2.30.61/c$\Qlikview_Tropal/apps/ventes")

'datetime.date' object has no attribute 'days' error while using timedelta

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

using datetime.utcnow() with DjangoTables2 render_FOO

I am trying to display the age of a post(in hours) with djangotables2. My code is given below
class PostTable(tables.Table):
current_Time = datetime.utcnow().replace(tzinfo=utc)
published= tables.Column()
def render_published(self, value,record):
tdelta = self.current_Time - record.published
#Some logic
With this code, 'current_Time' is only updated when the apache server restart. If I change my code to
tdelta = datetime.utcnow().replace(tzinfo=utc) - record.published
it works, but calculates datetime.utcnow() for every row which is not efficient. I want 'current_Time' to be updated only once for table. What is the best way to achieve that?
Try setting the current time in the table's __init__ method. Then self.current_Time will be set each time the table is initiated, rather than when the table is defined.
class PostTable(tables.Table):
def __init__(self, *args, **kwargs):
super(PostTable, self).__init__(*args, **kwargs)
self.current_Time = datetime.utcnow().replace(tzinfo=utc)
def render_published(self, value,record):
tdelta = self.current_Time - record.published
current_Time is a field on your class which is installed when your class deffinition is read in. This happens once when your class is initially defined. In your case, this happens at server startup. The value for current_Time is set then and only once.
You will want to move current_Time = datetime.utcnow().replace(tzinfo=utc) into the def render_published(self, value,record):
class PostTable(tables.Table):
published= tables.Column()
def render_published(self, value,record):
current_Time = datetime.utcnow().replace(tzinfo=utc)
tdelta = current_Time - record.published
#Some logic
This way, current_Time will be populated every time the render_published method is called.

Categories

Resources