Django set value to POST form - python

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.

Related

Django form DateInput: change date format from mm/dd/yyy to dd/mm/yy

I'm trying to change the default format of the date from mm/dd/YYYY to dd/mm/YYYY, but even adding a custom format (format="%d/%m%/%YYYY") the result doesn't change.
date = forms.DateField(initial=timezone.now(), widget=DateInput(attrs={'class': 'datepicker'}, format="%d/%m/%Y"), label="Data", error_messages=MY_DEFAULT_ERRORS)
To do so, I re-defined the DateInput class like this:
class DateInput(forms.DateInput):
input_type = 'date'
You need to pass input_formats to the DateField form field to override the accepted date input formats.
date = forms.DateField(
initial=timezone.now(),
input_formats=["%d/%m/%Y"],
widget=DateInput(attrs={'class': 'datepicker'}, format="%d/%m/%Y"),
label="Data",
error_messages=MY_DEFAULT_ERRORS
)

ValueError at / time data '' does not match format '%Y-%m-%d'

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

WTForms - DateTimeLocalField data is None after submit

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.

Parsing dates using WTForms Flask - Python

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.

Python/Django - datetime dropping the time portion when updating serializer data

I am using Django REST Framework, specifically a ModelSerializer instance, to receive some date/time information, among other fields. The Django form which POSTs or PUTs to my view is using a single field for date, and separate fields for hour, minute, and am/pm.
I wrote a function to deal with recombining the values into a Python datetime object, but for some reason, when my function returns a correct datetime, the time portion is getting zero'ed out when the datetime is assigned back to the serializer object for saving.
I am new to DRF so maybe I just need to approach this another way altogether....
def roomeventrequest(request, roomevent_id):
"""
THIS IS THE VIEW
"""
...
elif request.method == 'PUT':
data = JSONParser().parse(request)
roomevent = RoomEvent.objects.get(pk=roomevent_id)
serializer = RoomEventSerializer(roomevent, data=data)
if serializer.is_valid():
serializer.data['start_datetime'] = _process_datetime(serializer.validated_data['start_datetime'],
data['start_hour'],
data['start_min'],
data['start_ampm'])
serializer.data['end_datetime'] = _process_datetime(serializer.validated_data['start_datetime'],
data['end_hour'],
data['end_min'],
data['start_ampm'])
print (serializer.data['start_datetime'])
print (serializer.data['end_datetime'])
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
def _process_datetime(date_obj, hour, minute, ampm):
print (date_obj)
if ampm == 'am' and hour == 12:
hour = 0
elif ampm == 'pm':
hour += 12
return_date = date_obj.replace(minute=int(minute), hour=int(hour))
print(return_date)
return return_date
And the above outputs the following from the print statements:
2015-05-21 00:00:00
2015-05-21 08:00:00
2015-05-21 00:00:00
2015-05-21 09:00:00
2015-05-21T00:00:00
2015-05-21T00:00:00
Why is the resulting time portion blank? Where have I gotten off track here?
The problem you are seeing is that you are modifying the serializer data from the outside, which doesn't actually propagate to the data used internally. So even though you are changing the start_datetime and end_datetime fields, internally DRF still sees the datetime objects that only contain the date.
You have a few options
Validate the date fields in a separate serializer (or just manually) and construct the correct date input on your own.
Combine all of the date fields before passing them into the serializer, such that they match one of the Django datetime input formats.
Directly modify serializer.validated_data (instead of serializer.data) in your code. This is what is passed on to create and update.
I would recommend avoiding #3 for now, as the validated_data dictionary is designed to be read-only and that may be enforced in the future. So that leaves you with #1 and #2, both of which work require modifications to different parts of your code and work better for different situations.
The first option works best if your validation needs to return errors to the frontend that need to match the specific field, instead of just commenting on the incorrect date format. But it also requires the creation of a custom MultipartDatetimeSerializer that is used for validating across all of the fields.
from datetime import date, datetime, time
class MultipartDatetimeSerializer(serializers.Serializer):
date = serializers.DateField()
hour = serializers.IntegerField(
min_value=1,
max_value=12
)
minute = serializers.IntegerField(
min_value=0,
max_value=59,
)
period = serializers.ChoiceField(
choices=(
('am', 'A.M.', ),
('pm', 'P.M.', ),
)
)
def to_internal_value(self, data):
parsed_data = super(MultipartDatetimeSerializer, self).to_internal_value(data)
hour = parsed_data['hour']
if parsed_data['period'] == 'pm':
hour += 12
elif hour == 12:
hour = 0
time_data = time(
hour=hour,
minute=parsed_data['minute']
)
return datetime.combine(
date=parsed_data['date'],
time=time_data
)
def to_representation(self, instance):
"""
Convert a datetime to a dictionary containing the
four different fields.
The period must be manually determined (and set), so there
is some pre-processing that has to happen here.
"""
obj = {
"date": instance.date,
"hour": instance.hour,
"minute": instance.minute,
}
if obj["hour"] > 12:
obj["hour"] -= 12
obj["period"] = 'pm'
else:
if obj["hour"] == 0:
obj["hour"] = 12
obj["period"] = 'am'
return super(MultipartDatetimeSerializer, self).to_representation(obj)
This serializer can now be used to split a datetime into the date, hour, minute, and period components.
obj = datetime.now()
serializer = MultipartDatetimeSerializer(obj)
print(serializer.data)
As well as combine them back together
data = {
"date": "2015-01-01",
"hour": "11",
"minute": "59",
"period": "pm",
}
serializer = MultipartDatetimeSerializer(data=data)
if serializer.is_valid():
print(serializer.to_internal_value(serializers.validated_data))
else:
print(serializer.errors)
The second option works best if you just need to return an error saying that the data given is not an actual date. You can find a date format that closely matches what is being entered and then concatenate the incoming data to match that.
In your case, the closest date format appears to be %Y-%m-%d %I:%M %p which will match a date like 2015-01-01 11:59 PM.
So, all that is left is to set the date format of the date field on your serializer to accept the above format (as well as ISO 8601, the default), which is as simple as setting input_formats on the field to
['iso-8601', '%Y-%m-%d %I:%M %p']
And changing the data passed to the serializer to concatenate the incoming values to match the field
data = JSONParser().parse(request)
data['start_datetime'] = "%s %s:%s %s" % (data['start_datetime'], data['start_hour'], data['start_min'], data['start_ampm'], )
data['end_datetime'] = "%s %s:%s %s" % (data['end_datetime'], data['end_hour'], data['end_min'], data['end_ampm'], )
Note that I'm always using the %s modifier instead of the %d modifier as DRF can handle incorrect numbers being passed into the fields, and it prevents an unhandled exception from occurring when a string is passed in.

Categories

Resources