Upload any DateTime from CSV in Django - python

I am uploading CSVs in a django project but it shows error from laptop to laptop.
Models.py
date = models.DateTimeField(blank=True, null=True, default=datetime.date.today)
views.py
csv_file = request.FILES['file']
data_set = csv_file.read().decode('UTF-8')
io_string = io.StringIO(data_set)
next(io_string)
uploaded_by = request.user
for column in csv.reader(io_string, delimiter=',', quotechar='|'):
_, created = ItemBatch.objects.update_or_create(name=column[0], pid=column[1], quantity=column[2],date=column[8])
The problem is that it takes only this format :
YYYY-MM-DD HH:MM
I updated settings.py with this:
DATETIME_INPUT_FORMATS = [
'%Y-%m-%d %H:%M:%S',
'%d-%m-%Y %H:%M:%S',
'%Y-%m-%d %H:%M:%S.%f',
'%Y-%m-%d %H:%M',
'%Y-%m-%d',
'%m/%d/%Y %H:%M:%S',
'%m/%d/%Y %H:%M:%S.%f',
'%m/%d/%Y %H:%M',
'%m/%d/%Y',
'%m/%d/%y %H:%M:%S',
'%m/%d/%y %H:%M:%S.%f',
'%m/%d/%y %H:%M',
'%m/%d/%y',
'%d-%m-%Y %H:%M'
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Asia/Kolkata'
USE_I18N = True
USE_L10N = False
USE_TZ = False
error:
["'10-7-2019 12:00' value has an invalid format. It must be in
YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
What changes do I need to make such that it accepts every datetime format?
EDIT
as per rudraa's suggestion I defined my formats in the CustomManager function:
def get_date_value(self, value):
FORMATS = [
'%d-%m-%y %H:%M',
'%d-%y-%m %H:%M',
'%m-%d-%y %H:%M',
'%m-%y-%d %H:%M',
'%y-%m-%d %H:%M',
'%y-%d-%m %H:%M',
'%d/%m/%y %H:%M',
'%d/%y/%m %H:%M',
'%m/%d/%y %H:%M',
'%m/%y/%d %H:%M',
'%y/%m/%d %H:%M',
'%y/%d/%m %H:%M'
]
input_formats = FORMATS
But while uploading the file with 15/7/2019 18:30 format i.e '%d/%m/%Y %H:%M' it says:
redefinition of group name 'd' as group 6; was group 1 at position 133

From what I can see, DATETIME_INPUT_FORMATS is being used in django forms only. It will validate any date given in formats with DATETIME_INPUT_FORMATS. But when you are using the model directly to store the data, it will only accept data if its given in YYYY-MM-DD HH:MM. It evaluates the datetime string against this regex. So I would recommend to write a custom manager to convert the values to datetime format, and use it to create/update the value. For example:
from django.utils import formats
class CustomManager(models.Manager):
def custom_update_or_create(self,*args, **kwargs):
date_time_value = kwargs.pop('date', None)
if date_time_value:
kwargs['date'] = self.get_date_value(date_time_value)
return super(CustomManager, self).update_or_create(*args, **kwargs)
def get_date_value(self, value):
input_formats = [
'%d-%m-%y %H:%M',
'%d-%y-%m %H:%M',
'%m-%d-%y %H:%M',
'%m-%y-%d %H:%M',
'%y-%m-%d %H:%M',
'%y-%d-%m %H:%M',
'%d/%m/%y %H:%M',
'%d/%y/%m %H:%M',
'%m/%d/%y %H:%M',
'%m/%y/%d %H:%M',
'%y/%m/%d %H:%M',
'%y/%d/%m %H:%M'
]
for format in input_formats:
try:
return self.strptime(value, format)
except (ValueError, TypeError):
continue
def strptime(self, value, format):
return datetime.datetime.strptime(value, format)
And Use it in the model:
class ItemBatch(models.Model):
date = models.DateTimeField(blank=True, null=True, default=datetime.date.today)
# rest of the fields
objects = CustomManager()
Finally use that method to create/update new instances:
ItemBatch.objects.custom_update_or_create(name=column[0], pid=column[1], quantity=column[2],date=column[8])

You will need to add following in settings.py:
DATETIME_INPUT_FORMATS = [
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y', # '10/25/06'
]

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.

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

Calculate Field to remove time from datetime Python

I want to calculate the value of a new field by grabbing the date only (strip out the time) from the existing field DATE_VAL.
I keep getting errors however. Here is my code.
formatter_string = "%m%d%y"
arcpy.CalculateField_management("joined", "Date", dt.strftime("!DATE_VAL!", formatter_string), "PYTHON_9.3", "")
If I try the following:
arcpy.CalculateField_management("joined", "Date", "dt.strftime(!DATE_VAL!, formatter_string).date()", "PYTHON_9.3", "")
I get the following error:
ExecuteError: ERROR 000539: Error running expression: dt.strftime(u"5/1/2014 3:00:00 AM", formatter_string).date()
When I try the following:
formatter_string = "%m/%d/%Y %I:%M:%S %p"
arcpy.CalculateField_management("joined", "Date",
dt.strptime("!DATE_VAL!", formatter_string).date(), "PYTHON_9.3", "")
I get the error: ValueError: time data '!DATE_VAL!' does not match format '%m/%d/%Y %I:%M:%S %p'
datetime.datetime objects have a date method that will return a datetime.date object.
formatter_string = "%m/%d/%Y %I:%M:%S %p"
arcpy.CalculateField_management("joined", "Date",
"dt.strptime(!DATE_VAL!, formatter_string).date()", "PYTHON_9.3", "")
I found some code to use update cursor rather than the calculate field. This seems to work for my purpose. I probably should have posted this in the gis stack exchange. sorry.
arcpy.AddField_management("joined", "Date", "DATE")
rows = arcpy.UpdateCursor("joined")
for row in rows:
datetimeVal = row.getValue("DATE_VAL")
formattedTime = dt.strftime(datetimeVal, "%m/%d/%Y")
row.setValue("Date", formattedTime)
rows.updateRow(row)
del rows, row
Im not the arcpy guy but this should do:
Instead of:
arcpy.CalculateField_management("joined", "Date", "dt.strftime(!DATE_VAL!, formatter_string).date()", "PYTHON_9.3", "")
Do this:
date_format = '%m/%d/%Y'
formatter_string = '%m/%d/%Y %I:%M:%S %p'
arcpy.CalculateField_management("joined", "Date", "dt.strftime(!DATE_VAL!, formatter_string).date().strftime(date_format)", "PYTHON_9.3", "")

problems with DateTimeField filter in Django

Help please me)
I have error "[u"'data_date' value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]" and don't know how resolve it.
my models.py
class Data(models.Model):
main = models.ForeignKey(Main)
user = models.CharField(max_length=200)
description = models.TextField()
data_date = models.DateTimeField(['%Y-%m-%d %H:%M'])
priority = models.CharField(max_length=1)
end_date = models.DateTimeField(['%Y-%m-%d %H:%M'])
def __unicode__(self):
return self.description
def was_published_recently(self):
return self.data_date >= timezone.now() - datetime.timedelta(days=1)
my views.py
def index(request, onsuccess='/', onfail='/login/'):
today = date.today()
data_data=timezone.now()
formatted_datetime = formats.date_format(data_data, "SHORT_DATETIME_FORMAT")
problems_filter = Data.objects.filter(main_id=1).filter(data_date__range=['data_date', 'end_date']).order_by('-data_date').order_by('priority')[:101]
# problems_filter = Data.objects.filter(main_id=1).order_by('-data_date').order_by('priority')[:10]
When i'm use the commend string, it's work fine.
Example format:
28 | 1 | admin | hi | 2014-05-01 00:41:00 | 2 | 2014-06-01 00:00:00
It seems you have ignored seconds portion from the input string to convert to datetime.
data_date = models.DateTimeField( ['%Y-%m-%d %H:%M'] )
end_date = models.DateTimeField( ['%Y-%m-%d %H:%M'] )
+---------------------+-------------------+----------------+
| input_date_string | its_format | what_you_tried |
+---------------------+-------------------+----------------+
| 2014-05-01 00:41:00 | %Y-%m-%d %H:%M:%S | %Y-%m-%d %H:%M |
| 2014-06-01 00:00:00 | %Y-%m-%d %H:%M:%S | %Y-%m-%d %H:%M |
+---------------------+-------------------+----------------+
Change accordingly for both data_date and end_date fields.
data_date = models.DateTimeField( ['%Y-%m-%d %H:%M:%S'] )
end_date = models.DateTimeField( ['%Y-%m-%d %H:%M:%S'] )
Refer to: DATETIME_INPUT_FORMATS
Default:
(
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y', # '10/25/06'
)

strptime validation error django

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.

Categories

Resources