Hi So I've been using WTForms with success for a good period of time now.
The problem is on how to parse dates.
I've always used to assign variables according to form data as follows
firstname = form.firstname.data
This will store the user's input from the form data into my variable called "firstname", which works just fine, my problem is when it comes to dates.
I have the following code
WTForms Class
class BookingForm(Form):
start_date = DateField('Start Date', format='%m/%d/%Y')
end_date = DateField('End Date', format='%m/%d/%Y')
The booking route
#app.route('/book/', methods=['GET','POST'])
#login_required
def book():
try:
form = BookingForm(request.form)
if request.method == "POST" and form.validate():
start_date = form.start_date.data
end_date = form.end_date.data
# I Have also tried form.start_date.data.strftime('%m-%d-%Y') with no luck
...
The HTML Template {jinja}
<div class="col-md-4">
{{ render_date_field(form.start_date) }}
</div>
<div class="col-md-4">
{{ render_date_field(form.end_date) }}
</div>
I am also using datetime in python
from datetime import datetime
I've been trying to follow many docs on how to parse a date into a variable from a user input form with no luck, Does anybody know the right syntax?
Thanks
form.date_created.data returns a datetime.date object.
The month, day, and year attributes store these values as integers. There is no need to import the datetime to solve this problem.
You can use date.strftime('%m-%d-%y') to get a string representation such as "10-22-18".
form = BookingForm(request.form)
if request.method == "POST" and form.validate():
start_date = form.start_date.data
end_date = form.end_date.data
# print(type(start_date)) -> <class 'datetime.date'>
start_month = start_date.month
start_day = start_date.day
start_year = start_date.year
start_date_str = start_date.strftime('%m-%d-%y')
# and so on...
Take a look at the WTForms Documentation for DateField.
class wtforms.fields.DateField(default field arguments, format='%Y-%m-%d')
Same as DateTimeField, except stores a datetime.date.
You can check out more about the date object in the docs
Python Docs
Tip: if you had tried print(type(start_date)) to see what it prints, you probably would have figured it out on your own.
Related
I'm working on a project in which when users mention a specific date range from and to, the corresponding data gets printed. The page takes input from users through input type date when the specific date is mentioned the value of date passes to user_input_date_to and user_input_date_to. But when I'm executing I'm getting the error ValueError at / time data '' does not match format '%Y-%m-%d'
My views file
def indexview(request):
url=requests.get('https://data.covid19india.org/v4/min/timeseries.min.json')
json_data=url.json()
user_input_state=''
user_input_date_from=''
user_input_date_to=''
user_data_type=''
user_required_type=''
if request.method == 'POST':
user_input_state=request.POST.get('state')
x=request.POST['date_from']
user_input_date_to=request.POST['date_to']
user_data_type=request.POST.get('data_period')
user_required_type=request.POST.get('required_type')
#To store dates list
start_date =user_input_date_from
end_date = user_input_date_to
start_date_object = dt.datetime.strptime(start_date,"%Y-%m-%d").date()
end_date_object = dt.datetime.strptime(end_date,"%Y-%m-%d").date()
days = end_date_object - start_date_object
dates=[]
otp=[]
for i in range(days.days+1):
dates.append(str(start_date_object+dt.timedelta(days=i)))
for i in dates:
try:
otp.append(json_data[user_input_state]['dates'][i][user_data_type][user_required_type])
except KeyError:
otp.append(0)
dict_pass={
'dates':dates,
'otp':otp
}
return render(request,'index.html',dict_pass)
HTML date form
<input type="date" name="date_from"><br>
<input type="date" name="date_to">
The problem is, that you are trying to create datetime object of format '%Y-%m-%d' from the invalid user input (in your case it's empty string).
You should validate user input first, then do the business logic.
You could do it manually, or try to use existing libraries for the validation
(e.g. pydantic, marshmallow ...)
I wrote the following code:
date = self.request.query_params.get('date')
queryset = Fixture.objects.all().order_by('-date')
if(date):
date = pytz.utc.localize(datetime.strptime(date, "%Y-%m-%d")).astimezone(pytz.UTC)
queryset = Fixture.objects.filter(date__date=date).order_by('date')
Upon excuting this with date = "2020-09-02" the queryset returns values containing the date "2020-09-03". How come this happens and how can this be solved?
If you want to work with a date, why make it a datetime first? Your parsing could be simplified.
date = self.request.query_params.get('date')
queryset = Fixture.objects.all().order_by('-date')
if date:
date = datetime.strptime(date, "%Y-%m-%d").date()
queryset = Fixture.objects.filter(date__date=date).order_by('date')
But this parsing is also is sensitive for wrongly inserted data, and you'll get an error. Best practice imo would be creating a simple form with a DateField.
class ParseDateForm(forms.Form):
date = forms.DateField()
# This somewhere in a method
form = ParseDateForm(data=self.request.query_params)
queryset = Fixture.objects.all().order_by('-date')
if form.is_valid():
date = form.cleaned_data['date']
queryset = Fixture.objects.filter(date__date=date).order_by('date')
After form is submitted with a POST request, every Field data has its value, except DateTimeLocalField. Accessing DateTimeLocalField's data value is a type of None.
Form
class ArticleForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
category = SelectField(u'Category', choices=categories.choices)
town = StringField('Town', validators=[DataRequired()])
minimal_price = IntegerField('Minimal price')
article_image = FileField('Article_image', validators=[FileRequired()])
time_left = DateTimeLocalField('Time to end', validators=[InputRequired()],
format='%Y-%m-%d %H:%M:%S')
description = TextAreaField('Description', validators=[DataRequired()])
Validation: (tested with is_submitted, all work except for article_form.time_left.data which is None)
if article_form.validate_on_submit():
new_article = Article(name=article_form.name.data,
category=article_form.category.data,
town=article_form.town.data,
minimal_price=article_form.minimal_price.data,
article_image=name,
time_left=article_form.time_left.data, # <-- None
description=article_form.description.data,
user_id=current_user.id)
Any help to get data from DateTimeLocalField ?
Try changing the format of the DateTimeLocalField from
format='%Y-%m-%d %H:%M:%S'
to:
format='%Y-%m-%dT%H:%M'
Tip: you can print the actual content of the input field prior to the validation to confirm the correct formatting of the DateTimeLocalField field.
Use wtforms.fields.html5.DateTimeLocalField instead of wtforms.DateTimeLocalField. Set the format with date and time separated by a 'T'. If you would want the current time as the default value, set default parameter.
from wtforms.fields.html5 import DateTimeLocalField
class InterviewForm(Form):
posted = DateTimeLocalField('Posted:', default=datetime.today, format='%Y-%m-%dT%H:%M')
I did extensive research on the same problem, this is a hack but I still got the timestamp from the tag which looked like:
<input id="time_left" name="time_left" required type="datetime-local" value="2018-11-15T04:44">
You basically search for the timestamp from the tag returned by the tag
date = re.search('(\d{4})[/.-](\d{2})[/.-](\d{2})[T](\d{2})[:](\d{2})',
str(form.time_left)).group())
Let me know if the solution worked for you or if found a better solution to the problem.
I'm trying to take info from a few models and generate table entries in the model Calendar. I cannot get it to save the Calendar entry. Getting a TypeError. Eventually I would like this system to add calendar entries into the future based of the last scheduled monday. But currently this task will only be performed on mondays. But I would like to be able to project more than one week forward if possible.
Template:
<form action="{% url 'portal:custom_admin' %}" method="post">
{% csrf_token %}
<div style="background-color:red; width:15%;">
<button name="submit">Project</button>
DANGER! Only click on mondays, until future projecter can go based off futuremost monday generated into Calendar
</div>
</form>
View with which I am struggling:
def custom_admin(request):
"""
Displays MaxSettings, also
Takes time_slots and create a week of it into the future (only should be done on mondays)
Note:eventually this should be able to generate from the last monday in the calendar instead of today
"""
max_settings = MaxSettings.objects.filter()
time_slots = TimeSlots.objects.filter()
if request.method != 'POST':
pass
# Do nothing
else:
# Project A week forward
for slot in time_slots:
#there will be an if statement for each weekday
if slot.day.weekday == 'Monday':
new_entry = Calendar(
date=datetime.timedelta(days=7),
timeslot_A=slot.timeslot_A,
timeslot_B=slot.timeslot_B,
booked=False
)
new_entry.save()
return HttpResponseRedirect(reverse('portal:custom_admin'))
calendar = Calendar.objects.filter()
context = {
'max_settings': max_settings,
'calendar': calendar,
}
return render(request, 'portal/custom_admin.html', context)
Here are the relevant models:
class MaxSettings(models.Model):
"""
Everyweek day has its own specified open/close time, time slots along with number of available jobs
"""
MONDAY = 'Monday'
TUESDAY = 'Tuesday'
WEDNESDAY = 'Wednesday'
THURSDAY = 'Thursday'
FRIDAY = 'Friday'
SATURDAY = 'Saturday'
SUNDAY = 'Sunday'
WEEKDAY_CHOICES = (
(MONDAY, 'monday'),
(TUESDAY, 'tuesday'),
(WEDNESDAY, 'wednesday'),
(THURSDAY, 'thursday'),
(FRIDAY, 'friday'),
(SATURDAY, 'saturday'),
(SUNDAY, 'sunday'),
)
weekday = models.CharField(max_length=9, choices=WEEKDAY_CHOICES, )
operating = models.BooleanField()
start_work_time = models.TimeField()
end_work_time = models.TimeField()
def __str__(self):
"""Return a string representation of the model."""
return self.weekday
class TimeSlots(models.Model):
"""time slots along with number of available jobs for that slot"""
day = models.ForeignKey(MaxSettings, on_delete=models.CASCADE)
timeslot_A = models.TimeField()
timeslot_B = models.TimeField()
max_jobs = models.PositiveSmallIntegerField()
def __str__(self):
"""Return a string representation of the model."""
return '%s %s %s' % (self.timeslot_A, self.timeslot_B, self.day)
class Calendar(models.Model):
"""
this will get it details from TimeSlots and be generated into the future from the MaxSettings
"""
date = models.DateField()
timeslot_A = models.TimeField()
timeslot_B = models.TimeField()
booked = models.BooleanField()
Error Details:
TypeError at /custom_admin/
expected string or bytes-like object
Request Method: POST
Request URL: http://127.0.0.1:8000/custom_admin/
Django Version: 2.0
Exception Type: TypeError
Exception Value: expected string or bytes-like object
Exception Location: error location: /site-packages/django/utils/dateparse.py in parse_date, line 74
My guess would be that the error happens because you're using a datetime.timedelta as a value for the date property of your Calendar entry. What Django needs is a datetime.date.
To be more precise, Django needs a date (e.g.: "2018-01-17"), while you are only providing a difference between two dates (in your case: "7 days"). What your code should do is compute the date for the next Monday and then pass that value (cast as a datetime.date) to the Calendar.date property.
My views.py looks like that
def add_note(request):
registered = False
user = User.objects.get(username=request.user.get_username())
if request.method == 'POST':
note_form = NoteForm(data=request.POST)
if note_form.is_valid():
note = note_form.save()
note.save()
registered = True
else:
print(note_form.errors)
else:
pass
return render(request, 'note.html', {'note_form': NoteForm, 'registered': registered})
In my HTML i use <td><input type="datetime-local" id="id_data" name="data" ></td>
Data from this input is not valid because format is 2015-12-20T12:15, should be 2015-12-20 12:15
My question is:
It is possible to change data format in input? I need format like this 2015-12-20 12:15 (T switch to SPACE)
if not how change value of Data in views.py
You can specify what format does your datetime field accept from the form field in NoteForm, so that you can accept the default format:
data = forms.DateTimeField(input_formats=['%Y-%m-%d %H:%M', '%Y-%m-%dT%H:%M'])
If you insist on using your desired format, you might need to change your front end input to somehow have the format.
You can easily change the date format in your views usign embed python date functions. For example, you can use strptime and strftime, both datetime fuctions.
import datetime
new_date = datetime.datetime.strptime('07/12/2015', '%d/%m/%Y').strftime('%Y-%m-%d')
strptime receives your request date, and strftime convert that date to a custom format.