I have been working on building a questionnaire using flask-wtf. my questions has 30 questions and
will likely grow in the future.
From reading the flask-wtf documentation. I see that to the inputted data from a form is accessible like so "form.username.data".
username = StringField('Username')
#app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
if request.method == 'POST' and form.validate():
user = User(form.username.data)
db_session.add(user)
return redirect(url_for('login'))
return render_template('register.html', form=form)
My question:
my qusetionair form has many fields and would be illogical to have to enter form.FIELDNAME.data to get the inputted data for every field. i understand for a user registration form that it would be acceptable as there are only about 3-5 fields. However in my scenario (questionair form) this is not ideal
Solution i tried:
I named my fields question_1 question_2 qusetion_3 , then created a while look like below to dynamically enter the field name. however, flask-wtf complains "AttributeError: 'MyForm' object has no attribute 'question'"
if form.validate_on_submit():
string = 'q'
for i in range(30):
question = "q"+str(i)
field_name = form.question.data
answer_to_add = Answer(answers=field_name)
db.session.add(answer_to_add)
db.session.commit()
For people in the future who run into a similiar issue. The resolution is to simply use "form.data" and not specify a field as this will mean all fields are sent.
Code example:
if form.validate_on_submit():
answer = form.data
"do something"
You can find more useful info in the docs: https://wtforms.readthedocs.io/en/2.3.x/forms/?highlight=form#wtforms.form.Form.data
Related
Problem Description
Hi all, likely a simple solution to this issue. Basically, I have a SelectField where for one class of users it is not viewable so I'm not sending the parameter in the API to create the user. Now form.validate() is marking this as an invalid choice even though I'm adding None to the list of allowable choices. Not sure how to make heads or tails of this and I haven't seen this type of issue mentioned anywhere else.
Goal
Get WTForms to correctly check for None in the request so I can get the validation where it matters for other users and this "non-validation" where it doesn't apply.
Relevant code
class CustomerForm(Form):
customer_name = StringField('Customer Name', [InputRequired()])
groups = SelectField('Group')
#app.route("/Customers", methods=["POST"])
def customers_post():
logging.debug(request.form)
form = CustomerForm(request.form)
# Adding the various valid options for the group input
with dbConfig.Session() as session:
choices = session.execute(select(Group)).all()
form.groups.choices = [(choice[0].id, choice[0].name) for choice in choices]
form.groups.choices.append(('-1', ''))
form.groups.choices.append((None, '1'))
if request.method == 'POST' and form.validate():
...
return Response(status=201)
elif request.method == 'POST':
jsonErrors = json.dumps(form.errors, ensure_ascii=False)
return Response(jsonErrors, status=400, mimetype='application/json')
Request payload
Just in case this helps
customer_name=austin-test-4
another valid payload where I want to check the selected choice is a valid option
customer_name=austin-test-4&groups=4
I have edit form (modelform) and for that form I created a url something like /contacts/edit//
My view is method base view and I am passing the contact_id from my template to the view as parameter.
Then that's what I am doing:
def edit_contact(request, contact_id):
is_user_authenticated(request.user.is_authenticated)
contact_person = get_object_or_404(domain.Contact.contacts, pk=contact_id)
if request.method == 'POST':
form = forms.ContactPersonForm(request.POST, instance=contact_person)
if form.is_valid():
form.save()
return HttpResponseRedirect('/contacts/')
However that url can be reached by any user with just giving ID and basically you can edit any person you want.
I could do one more query to DB in order to find if a person is the right person to edit contact information but is that right way to do that? What's best practice for my situation?
Referencing the following Form.
CONTROL_CHOICES = Session.query(schema.OfficeType).order_by(schema.OfficeType.descr).all()
CONTROL_CHOICES = [(office.id, office.descr) for office in CONTROL_CHOICES]
class ControlForm(Form):
institution = RadioField('Institution', choices=CONTROL_CHOICES)
date = DateField('Date')
submit = SubmitField('SUBMIT')
Simple HTML
<form action="composition_profile" method="get">
{{control_form.hidden_tag()}}
{{control_form.institution.label}}
{{control_form.institution}}
{{control_form.date.label}}
{{control_form.date}}
{{control_form.submit}}
</form>
The radio fields are successfully printed.
However, when filling out the form, validate_on_submit() prints no errors, but does not execute code within the if
validate() prints the following error.
{'institution': ['Not a valid choice']}
#app.route('/composition_profile', methods=['GET', 'POST'])
def composition_profiles():
if request.method == 'GET':
if request.args.get('institution') and request.args.get('date'):
form = ControlForm(request.args)
print(form.institution.data)
if form.validate():
print('terms')
print(form.errors)
Any idea how it is resulting in an improper choice? Im not really sure what's going on. Changing it to QuerySelectField works, but I'd like the radio functionality
Consider re-factoring:
def my_view():
class F(MyBaseForm):
pass
F.username = TextField('username')
for name in iterate_some_model_dynamically():
setattr(F, name, TextField(name.title()))
form = F(request.POST, ...)
# do view stuff
Source: http://wtforms.simplecodes.com/docs/1.0.1/specific_problems.html#dynamic-form-composition
The Issue appears to have been caused due to the fact that WTForm expects the Value field, to be a String as opposed to an Integer
Changing
CONTROL_CHOICES = [(office.id, office.descr) for office in CONTROL_CHOICES]
To
CONTROL_CHOICES = [(str(office.id), office.descr) for office in CONTROL_CHOICES]
Alleviates the issue
I'm brand new to django and fairly new to programming in general. I've done the django tutorial and searched the web for an answer to this question, but to no avail, so now I'm here. I am confused how post works with django. All of the tutorials I've looked at how have a return function in views that displays the webpage. I get that. But then how does a user update data if the page is being rendered from that return statement? After the return there can't be any more updates because the function stops, right? What am I missing here? Any help would be greatly appreciated, I'm getting fairly desperate here.
One pattern for Django views (by no means the only pattern) is to check the request method (GET or POST) at the beginning of the view. If it is POST, then handle the incoming data (before the view returns), and then return either a rendered template, or a redirect.
def view_function(request):
if request.method == 'POST':
if data_is_valid(request.POST):
save_data(request.POST)
return HttpResponseRedirect('/somewhere/good')
else:
return render('template', {'errors': what_went_wrong}
else:
return render('template')
The user updates data in the logic of the view function. That is to say, if the user wishes to update something, you place the update logic in the view function before the return. For example, you would do this:
def update(request):
item = <some model>.objects.get(<something>)
<more code>
return <something>
Usually an edit view function contains two parts -- one for updating data, and the other for displaying the update form. For example,
def user_edit(request):
if request.method == 'POST': # is this a save action?
# save the user data
user_id = request.POST.get('user_id')
username = request.POST.get('username')
description = request.POST.get('description')
user = User.objects.get(id=user_id)
user.username = username
user.description = description
user.save()
return HttpResponseRedirect('/user/') # redirect to index
else:
# show the edit form
user_id = request.GET.get('user_id')
user = User.object.get(id=user_id)
return render_to_response('/user/edit.html', { 'user': user })
There are many different choices for the if request.method == 'POST' line. You can also use if request.POST.get('user_id') to check if specified field is set, to determine if this is a save action.
My view calls some backend classes which need some user input. When user input is required, i halt processing and store the questions into the session - request.session['questions']. request.session['questions'] is a list of dictionaries. e.g.
request.session['question'] = []
request.session['question'].append({'question' : 'Whats your firstname', 'answer' : ''})
request.session['question'].append({'question' : 'Whats your firstname', 'answer' : ''})
I need to display these questions to the user along with an input box for each question. When the user submits the form, I need to dump the input into the answers part of the session variable. Could someone show me how to do this? I'm a little lost as this isn't really based on Django forms or models as such.
Thanks
You could use forms that aren't associated with models, like this:
class QuestionForm(forms.Form):
answer = forms.CharField()
def questions(request):
if request.method == 'POST':
form = QuestionForm(request.POST)
if form.is_valid():
# Process the data in form.cleaned_data
return HttpResponseRedirect('/done/')
else:
form = QuestionForm() # An unbound form
return render_to_response('questions.html', {'form': form,})
More documentation here.