It is a work application that manages the reservation date of Django that I made a long time ago. Python is 2 system because it is an old one. Django is also old and 1.6.
It was compatible with 8-digit input, but ...
Like a Date picker It is cool in terms of UI to input the date by clicking with the mouse, It's easy for users to understand, It is quite troublesome if you need to input continuously. Just like everyone loves editors that don't require a mouse.
The default DateField is the keyword argument input_fields Text input is possible by specifying "% Y-% m-% d", "% Y /% m /% d", etc. Entering hyphens and slashes is quite troublesome. If possible, I want to complete it with just the numbers on the numeric keypad. (If you press Enter to move tabs) However, if you specify "% Y% m% d", there is no problem when you enter 8 digits, If there are not enough digits, how much is the year, how much is the month, and how much is the day The actual behavior will be confusing to the user.
If you specify "% m% d", the year is fixed at 1900. And, as with "% Y% m% d", the problem of the boundary between dates remains.
To solve it, you need to change the interpretation of the input value of Field. Actually, it's OK if you override the to_python function of DateField.
For the time being, after confirming that it is an 8-digit number
def to_python(self, value):
#abridgement
#Write the code elsewhere at the end
year_month_day = value[:4], value[4:6] , value[6:]
result = date(*map(int, year_month_day))
return result
Just like a date with 4 digits, 2 digits and 2 digits.
First, clear the boundary problem by narrowing down to only 4-digit numbers.
If it is 4 digits, there is only a date, so roughly Last year, this year, next year There are three possible patterns.
How to decide is important
Isn't it enough for the time being if it is implemented? If you manage the reservation date, you will use the nearest future date.
That's why the keyword argument determines the date selector at initialization. In terms of image
DateField("Future day", selecter="nearest_fortune")
DateField("Past day", selecter="nearest_past")
DateField("Soon", selecter="nearest")
It looks like the above.
In summary, the code is as follows.
class DateField(forms.DateField):
def __init__(self, *args, **kwargs):
#The name of the selecter should be wide to some extent
nearest = ["nearest_selecter", "nearest"]
fortune = ["nearest_fortune_selecter",
"nearest_fortune",
"fortune"]
past = ["nearest_past_selecter",
"nearest_past",
"past"]
#If you don't pop it, it's superclass__init__Get angry with "undefined arguments" when calling
selecter_name = kwargs.pop("selecter", None)
#Change the year selection method with the selecter keyword
if selecter_name in nearest:
self.selecter = self.nearest_selecter
if selecter_name in past:
self.selecter = self.nearest_past_selecter
if selecter_name in fortune:
self.selecter = self.nearest_fortune_selecter
else:
self.selecter = self.nearest_selecter
forms.DateField.__init__(self, *args, **kwargs)
#The one who selects the near past day
def nearest_past_selecter(self, days):
today = date.today()
get_days = lambda d: abs((today - d).days)
nearest = min(filter(lambda d: d <= today, days), key=get_days)
return nearest
#The one who chooses the near future day
def nearest_fortune_selecter(self, days):
today = date.today()
get_days = lambda d: abs((today - d).days)
nearest = min(filter(lambda d: d >= today, days), key=get_days)
return nearest
#The one who chooses the near day
def nearest_selecter(self, days):
today = date.today()
get_days = lambda d: abs((today - d).days)
nearest = min(days, key=get_days)
return nearest
@override
def to_python(self, value):
value = value.strip()
#For 4 digits
if len(value) == 4 and value.isdigit():
month, day = int(value[:2]), int(value[2:4])
today = date.today()
prev_year = date(today.year - 1, month, day)
this_year = date(today.year , month, day)
next_year = date(today.year + 1, month, day)
days = [prev_year, this_year, next_year]
return self.selecter(days)
#For 8 digits
elif len(value) == 8 and value.isdigit():
year_month_day = value[:4], value[4:6] , value[6:]
result = date(*map(int, year_month_day))
if result.year < 2000 or result.year > 2100:
message = u'Enter the year between 2001 and 2099.'
self.error_messages['invalid'] = message
raise ValidationError
else:
result = forms.DateField.to_python(self, value)
return result
Recommended Posts