I've a booking form in my template that sends an email when it's submitted. In my database the datetime field is shown like: Oct. 6, 2015, 3:58 p.m. But when I get the email the datetime field is shown like: 2015-10-06 15:58:50.954102 How do i format it such that in the email it's shown exactly like how it's shown in the database?
models.py
class Booking(models.Model):
patient_name = models.CharField(max_length=1300)
phone = models.IntegerField(null=True, blank = True)
preference = models.CharField(max_length=150,null = True, blank = True) #morning,noon,night
doctor = models.ForeignKey(Doctor)
clinic = models.ForeignKey(Clinic,null=True, blank = True)
datetime = models.DateTimeField(auto_now=True, auto_now_add=True, blank = True, null = True)
def __unicode__(self):
return u"%s %s" % (self.patient_name, self.doctor)
views.py
lead = Booking(doctor_id=doctor.id, clinic_id=doctor.clinic.id, preference=preference, patient_name=patient_name, phone=phone)
lead.save()
body = "Request Made: " + str(lead.datetime) +" "
email = EmailMessage('Blah', body, to=[clinic.email])
email.send()
You can format datestrings using strftime
>>> from datetime import date
>>> dt = date(2015, 10, 6, 15, 58, 50)
>>> dt.strftime("%b. %-d %Y %-I:%M %p")
'Oct. 6 2015 2:12 PM'
There's a list of the codes for strftime at at http://strftime.org/
So in your view you would do something like
body = "Request Made: %s " % lead.datetime.strftime("%b. %-d %Y %-I:%M %p")
Thats not exactly how it's in the database, it's just what the tool you use to view inside the database, displays datetime.
However if you want your datetime to look exactly like that, use:
lead.datetime.strftime("%b. %-d %Y %-I:%M %p")
Here are some relevant sources:
https://docs.python.org/2/library/datetime.html#datetime.datetime
https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior
Related
How do I implement functionality where a user can only update an entry when the date_created and date_modified fields of the diary entry are the same?
This is what I have implemented. I have compared the date_created field of the entry model in the db to datetime.date.today().
Data model
class DiaryEntry():
def __init__(self):
self.title = ''
self.body = ''
self.date_modified = None
self.date_created = datetime.date.today()
def save(self, current_user_email):
# insert data into db
query = "INSERT INTO entries (owner_id, title, body, date_created, date_modified) \
VALUES ((SELECT user_id from users where email ='{}'), '{}', '{}', '{}','{}')" \
. format(current_user_email,
self.title,
self.body,
self.date_created,
self.date_modified
)
db.execute(query)
Method
def update_diary_entry(self,entry_id):
query = "select * from entries where entry_id='{}'".format(entry_id)
result = db.execute(query)
entry = result.fetchone()
data = request.get_json()
date_created = entry[4]
if date_created == datetime.date.today():
query = "update entries set title='{}',body='{}' where entry_id='{}'"\
.format(data['title'], data['body'], int(entry_id))
db.execute(query)
return {'message': 'diary entry updated succesfully','date':date_created}, 406
else:
return {'message': 'diary entry can only be updated on the day it was created'}, 406
I am currently getting the second return statement. What could I be doing wrong?
It looks like you have date_created as a string (str) within update_diary_entry(). That will cause an invalid comparison to a Python datetime.date object unless you parse the string into the same type:
>>> import datetime
>>> date_created = '2018-07-29'
>>> date_created == datetime.date.today()
False
>>> datetime.datetime.strptime(date_created, '%Y-%m-%d').date() == datetime.date.today()
True
The classmethod strptime() parses a string that looks like a date into a datetime.datetime object. You need to then grab just the date component from this to enable the comparison that you want. If you have a differently-formatted date-string, see strftime() and strptime() Behavior.
I'm currently working in a Django project which defines a custom DateTimeField as follows (in dashboard/forms/fields):
import pytz
from datetime import date, datetime
from django import forms
from django.core.exceptions import ValidationError
from dashboard.forms.widgets import DateTimeWidget
class DateTimeField(forms.MultiValueField):
widget = DateTimeWidget
DATE_FORMAT = '%B %d, %Y'
TIME_FORMAT = '%I:%M %p'
DATETIME_FORMAT = f'{DATE_FORMAT} {TIME_FORMAT}'
def __init__(self, timezone_choices=None, timezone=None, **kwargs):
fields = (forms.CharField(), forms.CharField(), forms.CharField())
super().__init__(fields=fields, **kwargs)
self.timezone_choices = timezone_choices
self.timezone = timezone
#property
def timezone_choices(self):
return self._timezone_choices
#timezone_choices.setter
def timezone_choices(self, value):
self._timezone_choices = self.widget.timezone_choices = value
#property
def timezone(self):
return self._timezone
#timezone.setter
def timezone(self, value):
self._timezone = self.widget.timezone = value
def compress(self, data_list):
try:
date, time, zone = data_list
tz = pytz.timezone(zone)
dt = datetime.strptime(f'{date} {time}', self.DATETIME_FORMAT)
return tz.localize(dt)
except ValueError:
return None
This field is used in a form called SessionForm like so:
class SessionForm(forms.ModelForm):
class Meta:
model = Session
fields = [
'scheduled_for',
]
scheduled_for = DateTimeField(
required=False,
timezone_choices=Family.TIMEZONE_CHOICES
)
This form includes the following clean() method, which I'd like to test:
def clean(self):
cleaned_data = super().clean()
status = cleaned_data.get('status')
location = cleaned_data.get('location')
if status in [Session.SCHEDULED, Session.SCHEDULED_CALENDARED] and not cleaned_data.get('scheduled_for'):
self.add_error(
'scheduled_for',
f"This field is required if the status is '{Session.SCHEDULED}' or '{Session.SCHEDULED_CALENDARED}'.")
return cleaned_data
To this end, I've tried writing the following test:
class SessionCreateTest(TestCase):
def test_scheduled_session_with_scheduled_time_and_expert_and_location_is_valid(self):
scheduled_time = dateutil.parser.parse("5 January 2019 at 1:30 PM")
date = scheduled_time.strftime(DateTimeField.DATE_FORMAT)
time = scheduled_time.strftime(DateTimeField.TIME_FORMAT)
zone = pytz.country_timezones('US')[20] # 'America/Los_Angeles'
scheduled_for = (date, time, zone)
self.data.update(
status=Session.SCHEDULED,
scheduled_for=scheduled_for,
expert=ExpertFactory().id,
location=Session.AT_HOME)
form = SessionForm(data=self.data)
import ipdb; ipdb.set_trace()
Unfortunately, when I drop into the debugger, I see that the form still has errors:
> /Users/kurtpeek/Documents/Dev/lucy2/lucy-web/dashboard/tests/test_sessions.py(666)test_scheduled_session_with_scheduled_time_and_expert_and_location_is_valid()
665 import ipdb; ipdb.set_trace()
--> 666 self.assertTrue(form.is_valid())
667
ipdb> form.errors
{'scheduled_for': ["This field is required if the status is 'Scheduled' or 'Scheduled & Calendared'."]}
However, if I pass my input for this field to the field's compress() method, it seems to be 'parsed' correctly:
ipdb> field = DateTimeField()
ipdb> field.compress(scheduled_for)
datetime.datetime(2019, 1, 5, 13, 30, tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
I don't understand why this test is not passing? How could I 'break this down' further?
I suggest you put the break point inside the clean method of the form. Check the structure of scheduled_for inside cleaned_data dict. It should give you the answer you need to test it.
I tried to declared a variable contains of Datetime like this
ts1.departure_date = '2012-03-03 10:10:10'
but then I got this error
StatementError: (exceptions.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input.
I wonder what is the correct way to declare a variable with datetime format? Thanks in advance
First import the datetime class:
from datetime import datetime
Then create a datetime object and use that to set your attribute:
ts1.departure_date = datetime(2012, 3, 3, 10, 10, 10)
expiration_year = int(form.expiration_date.data[:4])
expiration_month = int(form.expiration_date.data[5:7])
expiration_date = int(form.expiration_date.data[8:10])
expiration_date =datetime(expiration_year,expiration_month,expiration_date)
Ultra strange error that encountered with SQLAlchemy with both SQLite and Postgres
from datetime import datetime
....
#WORKS
lending_operation = models.LendingOperation(
device_id = device.device_id,
start_using = datetime.now()
)
db.session.add(lending_operation)
db.session.commit()
#DIDN'T WORK
lending_operation = models.LendingOperation(
currency = "USD",
device_id = device.device_id,
start_using = datetime.now()
)
db.session.add(lending_operation)
db.session.commit()
#MODEL: models.py
class LendingOperation(db.Model):
.....
start_using = db.Column(db.DateTime, default=datetime.now )
.....
currency = db.Column(db.DateTime)
Hope it helps, didn't find any info on the exception
I want to convert date like Jun 28 in datetime format like 2014-06-28. I tried following code and many more variation which gives me correct output in ipython but I m unable to save the record in database. It throws error as value has an invalid date format. It must be in YYYY-MM-DD format. Can anyone help me to fix this issue ?
Following is the code snippet
m = "Jun"
d = 28
y = datetime.datetime.now().year
m = strptime(m,'%b').tm_mon
if m > datetime.datetime.now().month:
y=y-1
new_date = str(d)+" "+str(m)+" "+str(y)
new_date = datetime.datetime.strptime(new_date, '%b %d %Y').date()
my models.py is as
class Profile(models.Model):
Name = models.CharField(max_length = 256, null = True, blank = True)
Location = models.CharField(max_length = 256, null = True, blank = True)
Degree = models.CharField(max_length = 256, null = True, blank = True)
Updated_on = models.DateField(null = True, blank = True)
Code that saves to model is like
def save_record(self):
try:
record = Profile(Name= indeed.name,
Location = loc,
Degree = degree,
Updated_on = new_date,
)
record.save()
print "Record added"
except Exception as err:
print "Record not added ",err
pass
Thanks in advance
Once you have a date object, you can use the strftime() function to format it into a string.
Let's say new_date is your date object from your question. Then you can do:
new_date.strftime('%Y-%m-%d')
Btw, you can do the same with a datetime object too.
EDIT:
Double check whether your Updated_on field uses DateField or DateTimeField. That will affect whether you use a datetime.date() object or datetime.datetime() object, respectively.
I tried on console:
>>import datetime
>>datetime.datetime.strptime("Jun-08-2013", '%b-%d-%Y').date()
datetime.date(2013, 6, 8)
There are several errors in the code. So solution should be:
m = "Jun"
d = 28
if datetime.datetime.strptime("Aug",'%b').month > datetime.datetime.now().month:
y= (datetime.datetime.now() - relativedelta(years=1)).year #from dateutil.relativedelta import relativedelta
else:
y=datetime.datetime.now().year
new_date = str(m)+"-"+str(d)+"-"+str(y)
new_date = datetime.datetime.strptime(new_date, '%b-%d-%Y').date()
new_date is a date object, so it should be saved to models.DateField() without any problem(including format issues).
I have a daterangepicker from which the users set date. The choice of format is "DD MMM YYYY"
now to go with that i'm using
datetime.datetime.strptime(time, "%d %b %Y");
but still i am getting an error
Exception Value:[u"'01 Aug 2013' value has an invalid date format. It must be in YYYY-MM-DD format."]
any idea what might be going wrong? stuck on this for a while.
def form_valid(self, form):
new_obj = form.save(commit=False)
new_obj.date_pickup_from, new_obj.date_pickup_to = form.cleaned_data['pickup_daterange'].split(' to ')
new_obj.date_delivery_from, new_obj.date_delivery_to = form.cleaned_data['delivery_daterange'].split(' to ')
here are the forms
pickup_daterange = forms.CharField(
label=_('Pickup Within'),
widget=forms.TextInput(attrs={'class': 'daterange'}),
validators=[
RegexValidator(
regex=r'\d{2}\ \w{3}\ \d{4}\ to\ \d{2}\ \w{3}\ \d{4}',
message=_(u'Range must be of format "mm/dd/yyyy to mm/dd/yyyy"'),
code='invalid_range'
)
],
help_text=_('Within what dates do you want the pickup?')
)
delivery_daterange = forms.CharField(
label=_('Delivery Within'),
widget=forms.TextInput(attrs={'class': 'daterange'}),
validators=[
RegexValidator(
regex=r'\d{2}\ \w{3}\ \d{4}\ to\ \d{2}\ \w{3}\ \d{4}',
message=_(u'Range must be of format "mm/dd/yyyy to mm/dd/yyyy"'),
code='invalid_range'
)
],
help_text=_('Within what dates do you want the delivery?')
)
models.py
date_delivery_from = models.DateField(_('Date of Delivery From'), blank=True, null=True)
date_delivery_to = models.DateField(_('Date of Delivery To'), blank=True, null=True)
function in my form class from where i am calling strptime
def clean_delivery_daterange(self):
daterange_pattern = re.compile(r'(\d{2}\ \w{3}\ \d{4})\ to\ (\d{2}\ \w{3}\ \d{4})')
delivery_daterange = self.cleaned_data['delivery_daterange']
pickup_daterange = self.cleaned_data['pickup_daterange']
str_pickup_from, str_pickup_to = daterange_pattern.search(pickup_daterange).groups()
str_delivery_from, str_delivery_to = daterange_pattern.search(delivery_daterange).groups()
delivery_from = datetime.datetime.strptime(str_delivery_from, "%d %b %Y")
pickup_from = datetime.datetime.strptime(str_pickup_from, "%d %b %Y")
if delivery_from < pickup_from:
raise forms.ValidationError('Delivery dates cannot be before pickup dates')
return delivery_daterange
Your problem is that you're not actually returning the converted values.
delivery_daterange = self.cleaned_data['delivery_daterange']
[...]
return delivery_daterange
That just returns the same string, unparsed. You could do something like this instead:
def clean_delivery_daterange(self):
[...]
delivery_from = datetime.datetime.strptime(str_delivery_from, "%d %b %Y")
delivery_to = datetime.datetime.strptime(str_delivery_to, "%d %b %Y")
return (delivery_from, delivery_to)
def clean_pickup_daterange(self):
[...]
pickup_from = datetime.datetime.strptime(str_pickup_from, "%d %b %Y")
pickp_to = datetime.datetime.strptime(str_pickup_to, "%d %b %Y")
return (pickup_from, pickup_to)
And then in the view:
new_obj.date_pickup_from, new_obj.date_pickup_to = form.cleaned_data['pickup_daterange']
An alternate approach would be to simply return the text values, then convert to Date objects in your view:
def form_valid(self, form):
new_obj = form.save(commit=False)
pickup_start_string, pickup_end_string = form.cleaned_data['pickup_daterange'].split(' to ')
new_obj.date_pickup_from = strptime(pickup_start_string, "%d %b %Y")
#...etc
A more advanced approach would be to define a custom field to cover the concept of a date range, and define its to_python method to return, say, a tuple of Date objects.
Personally, I would simplify the whole thing and just let date_pickup_from and the rest be DateField instances in the form, maybe with a custom widget if I wanted to use something like a jQuery DatePicker to help the user pick the dates, and take care of special rendering in the template.