I still can't find a working solution, hence I decided to throw my first post. Note, I'm a beginner in Django.
Building a portal that displays days since the user has been verified.
I tested my model without using custom DateField (verified_since), just with date_joined, and it works properly - showing the count of days remaining (I countdown from 365 days, I am not worried about the leap year yet) since the user has registered in the database vs. today.
class Profile(models.Model):
verified_since = models.DateField(default=now)
#property
def ver_since(self):
return 365 - (now() - self.user.date_joined).days
Now if I use verified_since instead date_joined, I get an error. I suspect this is due to a different format of a date, or maybe a string format instead of a date which can't be subtracted then from datetime.now()
verified_since is manually entered date on the form by user.
class Profile(models.Model):
verified_since = models.DateField(default=now)
#property
def ver_since(self):
return 365 - (now() - self.user.verified_since).days
Here is settings:
TIME_ZONE = 'CET'
USE_I18N = True
USE_L10N = False
USE_TZ = True
TIME_INPUT_FORMATS = ('%H:%M',)
DATE_INPUT_FORMATS = ['%d/%m/%Y']
datetime.now() gives you datetime object, while your 'verified_since' is a date field. So just convert your current datetime to date.
>>> verified_since
datetime.date(2022, 4, 8)
>>> datetime.now().date()
datetime.date(2022, 4, 12)
>>> 365 - (datetime.now().date() - verified_since).days
361
PS: I don't know what ver_since is for, but logically speaking, it's definitely not "verified since - in days"
Related
I created a form with a DateField and a TimeField. When printing these from the routes.py I get these example values:
TimeField: 17:30:00
DateField: 2021-07-12
How can I turn those values into a datetime object, which I can submit to my Postgres Database? The required object format is DateTime. The Postgres Table is set up as TIMESTAMPTZ. I tried replace() to add the time to the DateField Data. But that does not work. I am new to datetimes and such, so please excuse my ignorance. How do the Timezones work? because I probably need to add the timezone somehow for the TIMESTAMPTZ, right?
Below is the minimal code for the functioning
forms.py
class CreateEvent(Form):
dt = DateField('DateTimePicker')
start_time = TimeField('Start')
submit = SubmitField("Submit")
models.py
class Events(db.Model):
__tablename__='events'
eid = db.Column(db.Integer, primary_key = True)
event_day = db.Column(db.DateTime, nullable=False)
start_time = db.Column(db.DateTime, nullable=False)
def __init__(self, event_day, start_time):
self.event_day = event_day
self.start_time = start_time
routes.py
if request.method == 'POST':
if form.validate() == False:
return render_template('create.html', form=form)
else:
event_day = form.dt.data
start_time = form.start_time.data
print(start_time)
print(event_day)
start_time = event_day.replace(time=start_time)
newevent = Events(event_day, start_time)
db.session.add(newevent)
db.session.commit()
return "Success"
Just in case, here is the Postgres Create Statement for the table:
CREATE TABLE events (
eid serial PRIMARY KEY NOT NULL,
event_day TIMESTAMPTZ NOT NULL,
start_time TIMESTAMPTZ NOT NULL,
);
pip install dateutil:
https://dateutil.readthedocs.io/en/stable/
then:
from dateutil.parser import parse
TimeField = "17:30:00"
DateField = "2021-07-12"
parse(DateField + ' ' + TimeField)
datetime.datetime(2021, 7, 12, 17, 30)
You probably don't need to add a timezone, Postgres will use the timezone setting for the server. Postgres does not actually store the timezone in a timestamptz field. It just uses the timezone setting to rotate the value to a UTC time for storage.
Not tested but as an example, and you may have to install pytz from PIP (if not already present on your system). Python knows so-called naive datetime objects (that have no timezone context), and time zone-aware datetime objects.
So the goal is to build a string with the date and the time, then parse it into a datetime object. Next, we add the desired time zone (in this example it is assumed US/Pacific so change as appropriate).
import datetime
import pytz
TimeField = "17:30:00"
DateField = "2021-07-12"
current_tz = pytz.timezone('US/Pacific')
# parse string into naive datetime object
dt_naive = datetime.datetime.strptime(f"{DateField} {TimeField}", "%Y-%m-%d %H:%M:%S")
# convert to time zone-aware datetime
dt_aware = current_tz.localize(dt_naive)
I have deployed my django project on digitalocean and it was working fine so far, until I made some changes to the way I was storing datetimes in my databases. I made them time-aware (before they were naive). Eventually, I ironed out all the bugs and my times were aware, and the project was working fine until I pulled the changes to my production server and when I tried to deploy it, it gave me the following error:
TypeError: combine() takes at most 2 arguments (3 given)
on this line:
start_time_in_local_time = datetime.datetime.combine(date, start_time, time_difference)
For context, this error happens every time I attempt to schedule a lesson with another user. I receive the timings and timezone information from the user, and I am trying to store the starting and ending times of that lesson in my database.
Here's the code:
def error_check_and_save_lesson(request, lesson, context):
# Get lesson timezone when (re)scheduling lessons
minutes_offset = request.POST.get('timezoneInfo','')
minutes_difference = int(minutes_offset)
time_difference = datetime.timezone(datetime.timedelta(minutes=minutes_difference))
# Get lesson name when (re)scheduling lessons
if not request.POST['name']:
context['name_error'] = True
else:
lesson.name = request.POST['name']
# Get lesson location when (re)scheduling lessons
if not request.POST['location']:
context['location_error'] = True
else:
lesson.location = request.POST['location']
# Get lesson date when (re)scheduling lessons
if not request.POST['date']:
context['date_error'] = True
else:
date = datetime.datetime.strptime(request.POST['date'], '%m/%d/%Y').date() # a date object.
# Get lesson starting time when (re)scheduling lessons
if not request.POST['startingTime']:
context['starting_time_error'] = True
else:
start_time = datetime.datetime.strptime(request.POST['startingTime'], '%I:%M %p').time() # a time object
# Get lesson ending time when (re)scheduling lessons
if not request.POST['endingTime']:
context['ending_time_error'] = True
else:
end_time = datetime.datetime.strptime(request.POST['endingTime'], '%I:%M %p').time()
lesson.tutor = request.user if request.user.profile.user_type == 'tutor' else context['person_to_schedule_with']
lesson.student = request.user if request.user.profile.user_type == 'student' else context['person_to_schedule_with']
if not context.get('name_error') and not context.get('location_error') and not context.get('date_error') and not context.get('starting_time_error') and not context.get('ending_time_error'):
utczone = datetime.timezone(datetime.timedelta(0)) # used to convert times in other timezones to UTC
start_time_in_local_time = datetime.datetime.combine(date, start_time) # THE BUG!
start_time_in_local_time=start_time_in_local_time.replace(tzinfo=time_difference)
end_time_in_local_time = datetime.datetime.combine(date, end_time)
end_time_in_local_time = end_time_in_local_time.replace(tzinfo=time_difference)
lesson.start_time = start_time_in_local_time.astimezone(utczone) # store starting time in UTC
lesson.end_time = end_time_in_local_time.astimezone(utczone) # store ending time in UTC
lesson.created_by = request.user
lesson.save()
context['schedule_success'] = "Your Lesson '" + lesson.name + "' Was Scheduled Successfully"
return context
I've checked the documentation (https://docs.python.org/3/library/datetime.html), the method takes 3 arguments, I'm especially confused because the exact action that's causing the bug in my project (scheduling lessons) works perfectly fine locally. I would guess this has something to do with my local database being sqlite and my production database being postgres, I'm not sure though.
Also, yes I have changed USE_TZ to True
Python 2 and Python 3 has different signature for the datetime.combine method
Python 2 method signature,
datetime.combine(date, time)
Python 3 method signature
datetime.combine(date, time, tzinfo=self.tzinfo)
I'm trying to group objects 'Event' by their 'due' field, and finally return a dict of day names with a list of events on that day. {'Monday': [SomeEvent, SomeOther]} - that's the idea. However while looking up event's due__day I get: int() argument must be a string, a bytes-like object or a number, not datetime.datetime.
Here's manager's code:
# models.py
class EventManager(models.Manager):
def get_week(self, group_object):
if datetime.datetime.now().time() > datetime.time(16, 0, 0):
day = datetime.date.today() + datetime.timedelta(1)
else:
day = datetime.date.today()
friday = day + datetime.timedelta((4 - day.weekday()) % 7)
events = {}
while day != friday + datetime.timedelta(1):
events[str(day.strftime("%A"))] = self.get_queryset().filter(group=group_object, due__day=day)
# ^^^ That's where the error happens, from what I understood it tries to convert this datetime to int() to be displayed by template
day += datetime.timedelta(1)
return events
Here is the model:
# models.py
class Event(models.Model):
title = models.CharField(max_length=30)
slug = models.SlugField(blank=True)
description = models.TextField()
subject = models.CharField(max_length=20, choices=SUBJECTS)
event_type = models.CharField(max_length=8, choices=EVENT_TYPES)
due = models.DateTimeField()
author = models.ForeignKey(User, blank=True)
group = models.ForeignKey(Group, related_name='events')
objects = EventManager()
I created a template filter to call this method:
#register.filter
def get_week(group_object):
return Event.objects.get_week(group_object=group_object)
And I called it in event_list.html (Using an index because it's a list view, also this is just temporary to see if the returned dict will be correct. Looping over it is to be implemented.)
{{ event_list.0.group|get_week }}
My guess is: I've broken something with this weird lookup. .filter(due__day=day) However I cannot find the solution.
I also tried to look for due__lte=(day - datetime.timedelta(hours=12)), due__gte=(day + datetime.timedelta(hours=12)) something like this but that doesn't work. Any solution is pretty much fine and appreciated.
Right, so the solution for my project is to check for due__day=day(the one from the loop).day <- datetimes property to compare day agains day not day against the datetime. That worked for me, however it does not necessarily answer the question since I don't exactly what caused the error itself. Feel free to answer for the future SO help seekers or just my information :)
This works for me:
Event.objects.filter(due__gte=datetime.date(2016, 8, 29), due__lt=datetime.date(2016, 8, 30))
Note that it uses date instead of datetime to avoid too much extraneous code dealing with the times (which don't seem to matter here).
forms.py
from django import forms
ACCEPTED_FORMATS = ['%d-%m-%Y', '%d.%m.%Y', '%d/%m/%Y']
class LeaveRequestForm(forms.Form):
start_date = forms.DateField(input_formats=ACCEPTED_FORMATS)
end_date = forms.DateField(input_formats=ACCEPTED_FORMATS)
working_days = forms.IntegerField(min_value=1)
I couldn't find any date format that could pass form validation, every time I received 'Enter a valid date.', so when I tried to define some the exception came out:
__init__() got multiple values for keyword argument 'input_formats'
https://docs.djangoproject.com/en/1.8/ref/forms/fields/#datefield
settings.py
...
USE_I18N = True
USE_L10N = True
...
I also tried built-in SelectDateWidget with no luck, every time produced invalid date. Maybe there is some "cache" issue:
"Enter a valid date" Error in Django Forms DateField
What should I do to get past this validation checks and move on with proper dates? Are the docs missing something with an error I encountered?
input_formats is not a kwarg, it's the sole option to DateField. Drop the input_formats=
ACCEPTED_FORMATS = ['%d-%m-%Y', '%d.%m.%Y', '%d/%m/%Y']
class LeaveRequestForm(forms.Form):
start_date = forms.DateField(ACCEPTED_FORMATS)
end_date = forms.DateField(ACCEPTED_FORMATS)
working_days = forms.IntegerField(min_value=1)
I am in the process of migrating an application from django 1.2 To 1.4.
I have a daily task object which contains a time of day that task should be completed:
class DailyTask(models.Model):
time = models.TimeField()
last_completed = models.DateTimeField()
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
weekends = models.BooleanField()
def __unicode__(self):
return '%s' % (self.name)
class Meta:
db_table = u'dailytask'
ordering = ['name']
In order to check if a task is still required to be completed today, I have the following code:
def getDueDailyTasks():
dueDailyTasks=[]
now = datetime.datetime.now()
try:
dailyTasks = DailyTask.objects.all()
except dailyTask.DoesNotExist:
return None
for dailyTask in dailyTasks:
timeDue = datetime.datetime(now.year,now.month,now.day,dailyTask.time.hour,dailyTask.time.minute,dailyTask.time.second)
if timeDue<now and timeDue>dailyTask.last_completed:
if dailyTask.weekends==False and now.weekday()>4:
pass
else:
dueDailyTasks.append({'id':dailyTask.id,
'due':timeDue,
'name': dailyTask.name,
'description':dailyTask.description})
return dueDailyTasks
This worked fine under 1.2, But under 1.4 I get the error:
can't compare offset-naive and offset-aware datetimes
due to the line
if timeDue<now and timeDue>dailyTask.last_completed
and both comparison clauses throw this error.
I have tried making timeDue timezone aware by adding pytz.UTC as an argument, but this still raises the same error.
I've read some of the docs on timezones but am confused as to whether I just need to make timeDue timezone aware, or whether I need to make a fundamental change to my db and existing data.
Check the thorough document for detail info.
Normally, use django.utils.timezone.now to make an offset-aware current datetime
>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2012, 5, 18, 13, 0, 49, 803031, tzinfo=<UTC>)
And django.utils.timezone.make_aware to make an offset-aware datetime
>>> timezone.make_aware(datetime.datetime.now(), timezone.get_default_timezone())
datetime.datetime(2012, 5, 18, 21, 5, 53, 266396, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)
You could then compare both offset-aware datetimes w/o trouble.
Furthermore, you could convert offset-awared datetime to offset-naive datetime by stripping off timezone info, then it could be compared w/ normal datetime.datetime.now(), under utc.
>>> t = timezone.now() # offset-awared datetime
>>> t.astimezone(timezone.utc).replace(tzinfo=None)
datetime.datetime(2012, 5, 18, 13, 11, 30, 705324)
USE_TZ is True 'by default' (actually it's False by default, but the settings.py file generated by django-admin.py startproject set it to True), then if your DB supports timezone-aware times, values of time-related model fields would be timezone-aware. you could disable it by setting USE_TZ=False(or simply remove USE_TZ=True) in settings.