Same datetime format for both display and input for DateTimeInput in Django
-
11-06-2021 - |
سؤال
By default Django displays date/time as something like May 13th, 2010, 4:01 p.m.
. I have also configured a jQuery calendar plugin (I used dateFormat: "MM d, yy", timeFormat: "h:mm tt"
and I modified the JavaScript source code to output a.m.
and p.m.
instead of AM
and PM
) to display the date/time in the same format.
But the form validation (by default) takes in the form of
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'
)
I tried to add '%B %d, %Y, %I:%M %p'
, but I'm not sure if %p
accounts for a.m.
and p.m.
(notice the periods after the letters). Here is a link to Python's documentation on the date/time formats.
How do you guys do this? Do you just stick with Django's default (ugly) date/time format or do you somehow convert the time before checking for form.is_valid()
(whether in JavaScript or Python)?
EDIT for @Thomas Orozco
I wrote a new form field called CustomDateTimeField
:
class CustomDateTimeField(forms.DateTimeField):
def strptime(self, value, format):
return datetime.datetime.strptime(value.replace("a.m.", "AM").replace("p.m.", "PM"), "%B %d, %Y, %I:%M %p")
However my form uses ModelForm
that has a dynamic fields
under class Meta
. Here is what I mean:
def order_edit(request, pk):
order = Order.objects.get(pk=pk)
if foo:
include_fields = (
'fa_date',
'sa_date',
)
else:
include_fields = (
'sa_date',
)
class OrderDetailForm(forms.ModelForm):
class Meta:
model = Order
fields = include_fields
if request.method == 'POST':
form = OrderDetailForm(data=request.POST, instance=order)
where Order.sa_date
and Order.fa_date
are both models.DateTimeField
. And I think I can only use DateTimeInput
for ModelForm
's widgets
. So how would I tell the form to use CustomDateTimeField
for OrderEditForm
? Do I need to add extra arguements via __init__
and manually redefine the fields like self.fields['fa_date'] = CustomDateTimeField(...)
?
المحلول
Initial answer
If you want your field to accept a particular format, the simpler solution would be to implement your own form field, which is usually pretty easy, especially here, given that Django handily provides you with an efficient base class.
Indeed, looking at the django source for the DateTimeField
, you can see that it inherits from BaseTemporalField
. Therefore, you'll only need to subclass BaseTemporalField
and implement the strptime
method so that it accepts your input format.
Said input format should be passed to your instance through the input_formats
variable, though this wouldn't be a requirement if you're willing to write a little bit more code.
You can also wade through the code for DateTimeField
and DateField
to get some inspiration.
Edit
You actually can override the fields of a ModelForm
: you just have to redefine them. In your situation, you however can't use a conditional block to do so (you can't have a if
statement in a class definition!). So you have two solutions:
class SAOrderDetailForm(forms.ModelForm):
class Meta:
model = Order
fields = ('sa_date',)
sa_date = CustomDateTimeField()
class FASAOrderDetailForm(SAOrderDetailForm): #Inheritance matters!
class Meta:
model = Order
fields = ('sa_date','fa_date')
fa_date = CustomDateTimeField()
if foo:
FormClass = FASAOrderDetailForm
else:
FormClass = SAOrderDetailForm
Alternatively, you could use dynamic creation of form classes , but that's sightly out of the scope of this question, so I'll leave you with this post from James Bennett that explains how to do so.
نصائح أخرى
What %p
renders depends on the locale being used. I am not sure if any locale provides for a.m.
/p.m.
.
However, the easiest way is to provide your own validation function for your form field. If this is a one-off field, simply override the clean_fieldname(self)
method of your form (where fieldname is the name of your datetime field). See cleaning a specific field attribute.
If this field is something you will be re-using, create a custom field with your validation logic and import and use it whenever you need your custom validation. You can also customize the widget to render any jquery selectors as well.