strptime validation error django - python

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.

Related

How Does Django Createsuperuser Know How To Parse My Date Field

I created a customized User module that adds a few extra fields:
class User(AbstractUser):
"""User modle for staff, clients and customers"""
username = None # remove username from the model
email = models.EmailField("email address", unique=True)
# """Email of user this will be used for login"""
address = models.OneToOneField(Address, on_delete = models.PROTECT, null=True, blank=True)
""":class:`Postal Address` associated with the User"""
birth_date = models.DateField()
"""Date of birth of User"""
phone = models.CharField(max_length=15)
"""Phone number of User"""
org = models.ForeignKey(Organization, on_delete=models.PROTECT, null=True, blank=True)
""":class:`Organization` User is associated with"""
# changes for using email instead of username
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'birth_date', 'phone']
objects = UserManager()
def __str__(self):
return F"{self.email} {self.first_name} {self.last_name}"
When I ran the createsuperuser command it asked me for birth_date (and knew how to parse it). I entered 2020-01-01 for the value.
Curious, I then temporarily put these statements in the createsuperuser function:
print("*****")
print(extra_fields)
print("*****")```
and got:
{'first_name': 'super', 'last_name': 'user', 'birth_date': datetime.date(2020, 1, 1), 'phone': '12345', 'is_staff': True, 'is_superuser': True, 'is_active': True}
How did it know to use datetime.date and how to parse it correctly?
More importantly, how can I make similar behavior for a custom related object?
How did it know to use datetime.date and how to parse it correctly?
It knows that it is a date because the birth_date is a DateField() object.
As for the format, it uses the formats in order that are defined in the DATE_INPUT_FORMAT setting [Django-doc]. By default these are:
[
'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
'%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
'%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
'%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
'%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
]
So here the first format is a match. If that produces an error when parsing, it moves to the next one, etc. until either one of the formats accepts the input, or the list is exhausted, in which case it will not be able to parse the date string.
You can alter the setting to use your own formats, or change the order to make a format more preferred over the other one. This can be important since 2020-05-06 can be parsed as May 6, or June 5. So if you add a format %Y-%d-%m in front of the list, it will be parsed differently.

Why can't I get a date from an rss feed and set it to my Django model?

I am using feed parser to create content from an rss feed. Its something like this:
import feedparser
def parse_rss(rss_url):
return feedparser.parse(rss_url)
def generate_content_from_feed(feed):
parsed_feed = parse_rss(feed.rss_url)
for item in parsed_feed['items']:
if not Content.objects.filter(link=item['link']).exists():
content = Content.objects.create(
title=item['title'],
link=item['link'],
description=item['description'],
pub_date=item['published'],
category=item['category'],
feed=feed,
)
if item['enclosure']:
content.media_url = item['enclosure']['url']
content.media_type = item['enclosure']['type']
content.save()
Now I am not entirely sure if the above code is working or not, as I can't test it.
In my models.py, I have these two models :
class Feed(models.Model):
rss_url = models.URLField()
def save(self, *args, **kwargs):
super(Feed, self).save(*args, **kwargs)
generate_content_from_feed(self) # Generating the content
class Content(models.Model):
title = models.CharField(max_length=500)
link = models.URLField()
description = models.TextField()
pub_date = models.DateTimeField(default=None)
category = models.CharField(max_length=500, blank=True)
media_url = models.URLField(blank=True) # Attached media file url
media_type = models.CharField(max_length=50, blank=True)
feed = models.ForeignKey(Feed, related_name='content_feed')
In case you are wondering, when a feed is saved, the content from that feed is generated and saved as Content objects in my database. Atleast thats what I am trying to do. However, when I save a feed, it gives an error saying something like this:
ValidationError at /admin/myapp/feed/add/
[u"'Fri, 08 Apr 2016 14:51:02 +0000' value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
How do I fix this problem? And also, I am no expert, could anybody tell me if my generate_content_from_feed method has issues or not? Thanks a lot.
There may be a better way but your code should look something like this
a = 'Fri, 08 A`enter code here`pr 2016 14:51:02 +0000'
dates = re.search(r'(\w+), (\d+) (\w+) (\d{4}) (\d+):(\d+):(\d+) ([\w+]+)', a)
# YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
day_str = dates.group(1)
day = dates.group(2)
month_str = dates.group(3)
year = dates.group(4)
hour = dates.group(5)
minute = dates.group(6)
second = dates.group(7)
new_date = "%s-%s-%s %s:%s:%s" % (year, month_str, day, hour, minute, second)
print(new_date)
>>> 2016-Apr-08 14:51:02
If you have problems again, its probably good trying to convert the Apr to a date number

Django 1.6 format datetime in views

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

How to convert string date in datetime.date format

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

Django - ValueError: "strftime format ends with raw %" when DATE_INPUT_FORMATS and TIME_INPUT_FORMATS are set?

In Django I have form that is using the SplitDateTimeField which is set to have an initial value as shown below. When try view the template containing the form I get ValueError: "strftime format ends with raw %."
# forms.py
class DiscountForm(Form):
title = CharField(widget=TextInput(), required=True)
description = CharField(widget=Textarea(), required=True)
fineprint = CharField(widget=Textarea(), required=True)
start = SplitDateTimeField(
input_date_formats='%m/%d/%Y',
input_time_formats='%I:%M %p',
initial= lambda: dt.datetime.now(),
required=True
)
end = SplitDateTimeField(
input_date_formats='%m/%d/%Y',
input_time_formats='%I:%M %p',
initial= lambda: dt.datetime.now() + dt.timedelta(days=30),
required=True
)
limit = IntegerField(min_value=0, initial=0, required=True)
# relevant in settings.py
USE_I18N = False
USE_L10N = False
USE_TZ = True
DATETIME_INPUT_FORMATS = ('%m/%d/%Y %I:%M %p')
DATE_INPUT_FORMATS = ('%m/%d/%Y')
TIME_INPUT_FORMATS = ('%I:%M %p')
Here is my traceback: http://dpaste.org/y55eV/
Any guidance is greatly appreciated. Thank you
The arguments input_date_formats and input_time_formats need to be lists or tuples, not strings (see SplitDateTimeField in documentation). The error may be caused that it is now iterating over characters instead of multiple input formats.
Try changing the code to the following:
start = SplitDateTimeField(
input_date_formats=('%m/%d/%Y',),
input_time_formats=('%I:%M %p',),
initial= lambda: dt.datetime.now(),
required=True
)
end = SplitDateTimeField(
input_date_formats=('%m/%d/%Y',),
input_time_formats=('%I:%M %p',),
initial= lambda: dt.datetime.now() + dt.timedelta(days=30),
required=True
)

Categories

Resources