Flask WTForms dynamic select field validation value is empty on POST - python

I am having trouble validating a dynamically generated WTForms SelectField. Somehow my self.choices is empty during POST while they are populated on the first GET request. Am I missing something?
app.py:
#app.route('/users/edit/<email>/', methods=['GET', 'POST'])
def users_edit(email):
match = False
for user in session['users']['message']:
if user['email']['S'] == email:
match = True
if match:
form = EditUserForm()
if request.method == 'GET':
form_data = session.get('edit_user_form_data', None)
if form_data:
form = EditUserForm(MultiDict(form_data))
form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
print(f"SHOPS_ALLOWED CHOICES WITH FORM DATA: {form.shops_allowed.choices}")
form.validate()
session.pop('edit_user_form_data', None)
else:
form.email.data = email
form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
print(f"SHOPS_ALLOWED CHOICES WITHOUT FORM DATA: {form.shops_allowed.choices}")
matched_shop = []
for user in session['users']['message']:
if user['email']['S'] == email and 'shops_allowed' in user.keys():
matched_shop = [allow['S'] for allow, shop in zip(user['shops_allowed']['L'], session['shops']['message'])]
form.shops_allowed.data = matched_shop
form.validate()
if request.method == 'POST' and form.validate_on_submit():
app.logger.info(f"PRE POST EDIT USER FORM DATA: {form.data}")
url = ...
<REDACTED POST REQUESTS ENDPOINT>
app.logger.info(f"POST EDIT USER RESPONSE: ({post_response.status_code}) {response_data}")
if post_response.status_code == 200:
session.pop('edit_user_form_data', None)
return redirect(url_for('users'))
else:
app.logger.info(f"EDIT USER FORM DATA: {form.data}")
session['edit_user_form_data'] = form.data
return redirect(url_for('users_edit', email=email))
elif request.method == 'POST' and form.validate_on_submit() == False:
app.logger.info(f"EDIT USER FORM DATA VALIDATION FAILED: {form.data}")
session['edit_user_form_data'] = form.data
return redirect(url_for('users_edit', email=email))
forms.py
class NonValidatingSelectMultipleField(SelectMultipleField):
def __len__(self):
return 1
def pre_validate(self, form):
pass
# HACK TO VALID A CHOICE FOR SELECT MULTIPLE
if self.data:
print(f"SELF DATA: {self.data}")
print(f"VALUES: {self.choices}")
values = list(self.coerce(c[0]) for c in self.choices)
print(f"PROCESSED VALUES: {values}")
for d in self.data:
if d not in values:
raise ValueError(self.gettext("'%(value)s' is not a valid choice for this multiple select field") % dict(value=d))
class EditUserForm(FlaskForm):
email = StringField('Email', [
validators.DataRequired(),
validators.Length(min=6),
validators.Email(message='Not a valid email address.')]
)
shops_allowed = NonValidatingSelectMultipleField(
'Shops',
widget = widgets.ListWidget(prefix_label=False),
option_widget = widgets.CheckboxInput(),
coerce=str
)
This renders the following logging:
SHOPS_ALLOWED CHOICES WITHOUT FORM DATA: [('decb5a00-fe45-484f-b887-b9bd41c4f0f2', 'My shop'), ('2cea2efa-7ccf-4bca-896d-16119d5fb7a8', 'My other shop')]
SELF DATA: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
VALUES: [('decb5a00-fe45-484f-b887-b9bd41c4f0f2', 'My shop'), ('2cea2efa-7ccf-4bca-896d-16119d5fb7a8', 'My other shop')]
PROCESSED VALUES: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
127.0.0.1 - - [03/Apr/2020 14:30:11] "GET /users/edit/my#email.com/ HTTP/1.1" 200 -
After POST:
SELF DATA: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
VALUES: None
And on screen:
forms.py", line 35, in pre_validate values = list(self.coerce(c[0]) for c in self.choices) TypeError: 'NoneType' object is not iterable

Meh, after going over my code once more I finally found the issue. I am calling form.validate_on_submit() at the same time I am verifying if request.method == 'POST' which never gives me the possibility to populated the choices during POST.
Changed my code to be:
if request.method == 'POST':
form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
form.validate_on_submit()
And it started to work. Sometimes you just need to write things down to see the answer :-)

Related

How to GET all the ALL DATA from WTForm?

**How To get All Data in a wtf form with a single command in a dictionary or list without needing to write this much lines of code, specifing every single element in the form and geting data seperately
**
#app.route('/add', methods=['POST', 'GET'])
def add_cafe():
form = CafeForm()
if form.validate_on_submit():
print("True")
cafe_name = form.cafe_name.data
cafe_location = form.cafe_location.data
opening_time = form.opening_time.data
closing_time = form.closing_time.data
coffee_rating = form.coffee_rating.data
wifi_strength_rating = form.wifi_strength_rating.data
power_socket_availability = form.power_socket_availability.data
return render_template('add.html', form=form)
The wtforms documentation says that that's Form.data:
A dict containing the data for each field.
In other words,
#app.route('/add', methods=['POST', 'GET'])
def add_cafe():
form = CafeForm()
if form.validate_on_submit():
data = form.data
print("True", data)
# ...
return render_template('add.html', form=form)

i am making a django website with multiple forms also used foregin key ValueEror :The view Capp.views.InsertProduct didn't return anHttpResponseobject

i am making a django website with multiple forms also used foregin key(user_id) to link one form with other in the database but at the last i get value error the error is:Exception Type: ValueError
Exception Value:
The view Capp.views.InsertProduct didn't return an HttpResponse object. It returned None insteated ,
the following is view.py file code(not complete code but only where error can lie)models.py part
def InsertProduct(request):
if request.method == 'POST':
if request.POST.get('user_id') and request.POST.get('pname') and request.POST.get('pcategory') and request.POST.get('pdetails') and request.POST.get('foundedin') and request.POST.get('orderoftest') and request.POST.get('t1') and request.POST.get('t2') and request.POST.get('t3') and request.POST.get('f1') and request.POST.get('f2') and request.POST.get('f3') and request.POST.get('f4') and request.POST.get('f5'):
saveproduct = ProInsert()
saveproduct.user_id = request.POST.get('user_id')
saveproduct.pname = request.POST.get('pname')
saveproduct.pcategory = request.POST.get('pcategory')
saveproduct.pdetails = request.POST.get('pdetails')
saveproduct.foundedin = request.POST.get('foundedin')
saveproduct.orderoftest = request.POST.get('orderoftest')
saveproduct.t1 = request.POST.get('t1')
saveproduct.t2 = request.POST.get('t2')
saveproduct.t3 = request.POST.get('t3')
saveproduct.f1 = request.POST.get('f1')
saveproduct.f2 = request.POST.get('f2')
saveproduct.f3 = request.POST.get('f3')
saveproduct.f4 = request.POST.get('f4')
saveproduct.f5 = request.POST.get('f5')
checkpname = ProInsert.objects.filter(
pname=saveproduct.pname).first()
return render(request, 'product_details.html')#here I had add what u said sir
if checkpname:
msgpname = messages.success(request, 'The user with Product Name ' +
request.POST['pname']+' already exist...!')
return render(request, 'product_details.html', {'msgpname': msgpname})
saveproduct.save()
messages.success(request, 'Product Added..!')
return render(request, 'product_details.html')
else:
return render(request, 'product_details.html')
I think you got it wrong I have update your code and commented the part i was telling you.
def InsertProduct(request):
if request.method == 'POST':
if request.POST.get('user_id') and request.POST.get('pname') and request.POST.get('pcategory') and request.POST.get('pdetails') and request.POST.get('foundedin') and request.POST.get('orderoftest') and request.POST.get('t1') and request.POST.get('t2') and request.POST.get('t3') and request.POST.get('f1') and request.POST.get('f2') and request.POST.get('f3') and request.POST.get('f4') and request.POST.get('f5'):
saveproduct = ProInsert()
saveproduct.user_id = request.POST.get('user_id')
saveproduct.pname = request.POST.get('pname')
saveproduct.pcategory = request.POST.get('pcategory')
saveproduct.pdetails = request.POST.get('pdetails')
saveproduct.foundedin = request.POST.get('foundedin')
saveproduct.orderoftest = request.POST.get('orderoftest')
saveproduct.t1 = request.POST.get('t1')
saveproduct.t2 = request.POST.get('t2')
saveproduct.t3 = request.POST.get('t3')
saveproduct.f1 = request.POST.get('f1')
saveproduct.f2 = request.POST.get('f2')
saveproduct.f3 = request.POST.get('f3')
saveproduct.f4 = request.POST.get('f4')
saveproduct.f5 = request.POST.get('f5')
checkpname = ProInsert.objects.filter(
pname=saveproduct.pname).first()
# return render(request, 'product_details.html')# NO need to add here as code below will be dead in this case.
if checkpname:
msgpname = messages.success(request, 'The user with Product Name ' +
request.POST['pname']+' already exist...!')
return render(request, 'product_details.html', {'msgpname': msgpname})
saveproduct.save()
messages.success(request, 'Product Added..!')
return render(request, 'product_details.html')
else:
return render(request, 'product_details.html')# What i meant was to add it here
else:
return render(request, 'product_details.html')

Flask: Bad Request POST 400

I use flask and firebase. I have 2 button in satis.html . When user press button2 , i want to retrieve some data from database and show it. But i get " Bad Request " Error.
Heres my code :
#app.route('/satis', methods=['GET', 'POST'])
def satis():
if (request.method == 'POST'):
sehir=request.form['il']
yas=request.form['yas']
id=request.form['id']
gun=request.form['satisgunu']
cins=request.form['cinsiyet']
tarz=request.form['satistarzi']
db = firebase.database()
db.child("names").push({"sehir": sehir,"yas":yas,"id":id,"gun":gun,"cins":cins,"tarz":tarz})
todo = db.child("names").get()
to = todo.val()
if request.form['submit'] == 'add':
db = firebase.database()
users_by_score = db.child("names").order_by_child("id").equal_to("2").get()
us = users_by_score.val()
return render_template('satis.html', t=to.values(),u=us.values())
return render_template('satis.html', t=to.values())
You have only handled for post method. You need to also handle the GET method situation.
#app.route('/satis', methods=['GET', 'POST'])
def satis():
db = firebase.database()
todo = db.child("names").get()
to = todo.val()
if (request.method == 'POST'):
sehir=request.form['il']
yas=request.form['yas']
id=request.form['id']
gun=request.form['satisgunu']
cins=request.form['cinsiyet']
tarz=request.form['satistarzi']
db.child("names").push({"sehir": sehir,"yas":yas,"id":id,"gun":gun,"cins":cins,"tarz":tarz})
if request.form['submit'] == 'add':
db = firebase.database()
users_by_score = db.child("names").order_by_child("id").equal_to("2").get()
us = users_by_score.val()
return render_template('satis.html', t=to.values(),u=us.values())
return render_template('satis.html', t=to.values())

Pyodbc Error 07002 - Count field incorrect or syntax error - Insert Data From Form

I've been building a webapp for the HR department which will (hopefully) include the ability for staff to submit timesheets and I have become stuck when trying to submit a timesheet. The connection string is working as I can see other data from the database. I have been working through errors but this 07002 error is one I can't work out what is causing it.
I've tried two different ways to get this working. Here is the first attempt in my app.py file -
#app.route('/timesheet', methods=['GET', 'POST'])
def employee_timesheet():
if request.method == "POST":
employee_id = request.form['employee_id']
department = request.form['department']
mondaystart = request.form['mondaystart']
mondayend = request.form['mondayend']
tuesdaystart = request.form['tuesdaystart']
tuesdayend = request.form['tuesdayend']
wednesdaystart = request.form['wednesdaystart']
wednesdayend = request.form['wednesdayend']
thursdaystart = request.form['thursdaystart']
thursdayend = request.form['thursdayend']
fridaystart = request.form['fridaystart']
fridayend = request.form['fridayend']
saturdaystart = request.form['saturdaystart']
saturdayend = request.form['saturdayend']
result = request.form
cursor = cnxn.cursor()
cursor.execute('''INSERT INTO dbo.submitted_timesheet (employee_id, department, mondaystart, mondayend, tuesdaystart, tuesdayend, wednesdaystart, wednesdayend, thursdaystart, thursdayend, fridaystart, fridayend, saturdaystart, saturdayend,) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)''')
cnxn.commit()
flash("Your form was successfully submitted")
print("Form data submitted")
return redirect (url_for('success.html', result=result))
return render_template("staff_timesheets.html")
The other way then is -
#app.route('/timesheet', methods=['GET', 'POST'])
def employee_timesheet():
if request.method == "POST":
employee_id = request.form['employee_id']
department = request.form['department']
mondaystart = request.form['mondaystart']
mondayend = request.form['mondayend']
tuesdaystart = request.form['tuesdaystart']
tuesdayend = request.form['tuesdayend']
wednesdaystart = request.form['wednesdaystart']
wednesdayend = request.form['wednesdayend']
thursdaystart = request.form['thursdaystart']
thursdayend = request.form['thursdayend']
fridaystart = request.form['fridaystart']
fridayend = request.form['fridayend']
saturdaystart = request.form['saturdaystart']
saturdayend = request.form['saturdayend']
insert_query = '''INSERT INTO submitted_timesheet (employee_id, department, mondaystart, mondayend, tuesdaystart, tuesdayend, wednesdaystart, wednesdayend, thursdaystart, thursdayend, fridaystart, fridayend, saturdaystart, saturdayend,) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
result = request.form
cursor = cnxn.cursor()
cursor.execute(insert_query, values)
cnxn.commit()
flash("Your form was successfully submitted")
print("Form data submitted")
return redirect (url_for('success.html', result=result))
return render_template("staff_timesheets.html")
If I submit a timesheet, I get the Pyodbc error in the title. Everything matches up in terms of column names and types. The HTML form should be fine too but can post it if needed for context.
Any ideas where I am going wrong?
Thank you!

django testing response.context TypeError: 'NoneType' object is not subscriptable

I want to test this view:
def register(request):
"""
handle user registration
code variable is for testing purposes
"""
if request.method== 'GET':
form = RegisterForm(auto_id=False)
code = 1
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
elif request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
password = form.cleaned_data['password']
password_confirmation = form.cleaned_data['password_confirmation']
if password == password_confirmation:
#if True:
login = form.cleaned_data['login']
email = form.cleaned_data['email']
newsletter = form.cleaned_data['newsletter']
key = register_user(login,email,password,newsletter)
if key:
#send email
send_mail("Dziękujemy za rejestrację"," Klucz aktywacyjny to " + key,settings.EMAIL_HOST_USER,[email])
request.session['email'] = email
return redirect(register_success)
else:
code = 4
error = "Login /email are taken"
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
else:
code = 3
error = "invalid password"
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
else:
code = 2
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
And here is my part of my test:
def test_valid_credentials(self):
#now try to register valid user
data = {'login':'test','password':'zaq12wsx','password_confirmation':'zaq12wsx','terms':True,'newsletter':True,'email':'test#test.com'}
response = self.c.post(reverse('register'),data)
#our user should be registred
self.assertEquals(302, response.status_code,'We dont have benn redirected')
self.assertEqual(len(mail.outbox), 1,'No activation email was sent')
#clen email box
mail.outbox = []
#now try to add anotheer user with the same data
response = self.c.post(reverse('register'),data)
#template should be rendered with error message about used login and email
self.assertEqual(response.context['code'],4)
And here is the error that I got:
,
in test_valid_credentials
self.assertEqual(response.context['code'],4)
TypeError: 'NoneType' object is not subscriptable
I tried it with get method and it works perfectly. Just with post it don't want to work.What am I doing wrong?Best regards
What is the response status? Redirects doesn't have context. Anyway, printing the response should help.
My guess is
key = register_user(login,email,password,newsletter)
throws an exception on duplicate register attempts and thus the handler does not generate a response.

Categories