I have multiple forms with one submit button for each of them, all in one template. render_template returns only empty StringFields. How can I render without touching my other StringFields?
#app.route('/', methods=['GET','POST'])
def index():
msform = msForm(request.form)
synform = synForm(request.form)
if request.method == 'POST' and msform.validate() and msform.ms_submit.data:
processed_text = model.most_similar(positive=[msform.ms_3.data, msform.ms_2.data], negative=[msform.ms_1.data])
msform.ms_submit.label.text = processed_text[0][0]
return render_template('my-form.html', msform=msform, synform=synform)
elif request.method == 'POST' and synform.validate() and synform.syn_submit:
processed_text = model.most_similar([synform.syn_1.data])
return render_template('my-form.html', msform=msform, synform=synform)
return render_template('my-form.html', msform=msform, synform=synform)
class msForm(Form):
ms_1 = StringField(label='Eingabe_1', default = 'king', validators=[validators.DataRequired(message='This Field is required')])
ms_2 = StringField(label='Eingabe_2', default = 'man', validators=[validators.DataRequired(message='This Field is required')])
ms_3 = StringField(label='Eingabe_3', default = 'queen', validators=[validators.DataRequired(message='This Field is required')])
ms_submit = InlineSubmitField(label = '?')
class synForm(Form):
syn_1 = StringField(label='Eingabe', default = 'king', validators=[validators.DataRequired()])
syn_submit = InlineSubmitField('?')
I am assuming you have two separate <form>s on your HTML page, like this for brevity:
<form>{{ msform }}</form>
<form>{{ synform }}</form>
I believe you are saying this: upon completing and submitting one form, the values are lost from the other. Is that correct?
If so, that's the expected behavior, not from Flask, but from your browser. When you submit an HTML <form>, only the data from that form tag is sent to the server. Therefor, any data in other <form> tags is lost.
To submit all forms, render all the forms in the same <form> tag. Give each form a prefix to ensure the input names don't collide.
msform = msForm(request.form, prefix='ms')
<form method="post">
{{ msform }}
{{ synform }}
</form>
Related
There is a drop-down list of items. If send button is pressed, the elements of the object are handled and I get a certain result. I want to check if the object is empty, then redirect to another page?
The code:
html:
<form action = "" method = "POST" enctype = "multipart / form-data">
<select id = 'sel' name = 'sel' class = "selectpicker sel" multiple data-live-search = "true">
{% for elem in elements%}
<option id = "val" value = "{{elem}}"> {{elem}} </option>
{% endfor%}
</select>
<button> Send </button>
</form>
python:
# app.route ('/', methods = ['GET', 'POST'])
def index ():
if request.method == 'GET':
return render_template ('index.html', elements = elements) # get all the elements on the page
elif request.method == 'POST':
docs = request.form.getlist ('sel') # here I get the items selected from the list
result = handler.dosomething (docs) # handler function
return render_template ('handler.html', result = result)
else:
pass
How to check if docs is empty and there are no selected elements inside this variable, then when the button is pressed, redirect to another page, for example error.html?
You can add one more if statement. See below:
# app.route ('/', methods = ['GET', 'POST'])
def index ():
if request.method == 'GET':
return render_template ('index.html', elements = elements) # get all the elements on the page
elif request.method == 'POST':
docs = request.form.getlist ('sel')
if len(docs)>0:
result = handler.dosomething (docs)
return render_template('handler.html', result = result)
else:
return render_template('error.html')
I have a form that's being given a dictionary of selection, it populates it correctly but on form submit it is not valid. When attempting to print errors, non_field_errors there are just blanks. When I am redirected to the form, now the choice field is populated by one choice and the csrf token from previous submit.
I've tried assigning choices in different ways such as self.fields['calendar'] = forms.ChoiceField(choices=choice_list) directly assign in a different way. self.fields['calendar'].choices = choice_list, a custom validator that ignores the validation, and inline debugging.
Form model:
class CalendarSelectionForm(forms.Form):
calendar = forms.ChoiceField(label="Calendar")
def __init__(self, calendars=None, *args, **kwargs):
super(CalendarSelectionForm, self).__init__(*args, **kwargs)
choice_list = [(calendar_id, calendar_name) for calendar_id, calendar_name in calendars.items()]
if calendars:
self.fields['calendar'].choices = choice_list
View:
if request.method == "POST":
print(request.POST)
cal_sync_form = CalendarSelectionForm(request.POST)
print("Non-field errors " + str(cal_sync_form.non_field_errors()))
print("Reg form errors " + str(cal_sync_form.errors))
# print("Field val " + str(cal_sync_form.calendar))
print("Field data " + str(cal_sync_form.data))
print("Field fields " + str(cal_sync_form.fields) + " Form is " + str(cal_sync_form.is_valid()))
if cal_sync_form.is_valid():
data = cal_sync_form.cleaned_data
print(data)
return render(request, 'management/gcal_sync_dashboard.html')
else:
return render(request, 'management/acct_select.html', {'form': cal_sync_form})
Form template:
<form class="form-import" action="/manage/gcal/sync/" method="post" id = "">
{% csrf_token %}
{{ form.calendar }}
{{ form.errors }}
{{ form.non_field_errors }}
<div class="push clearfix"></div>
<div class="col-sm-6 no-pad push"><input class="btn btn-brand btn-little button filson push-half" type="submit" value="Select email"><i class="fa fa-plus"></i></input>
</div>
</form>
The goal is to validate a posted form, the current print statements print out
<QueryDict: {'csrfmiddlewaretoken': ['sJHE8JJAzmeS0nRjaYZg5KdMlevJiInYY0G4YFJeITH1cVjciIdR1Dq1N28loUIL'], 'calendar': ['email#email.io']}>
Non-field errors
Reg form errors
Field data {}
Field fields OrderedDict([('calendar', <django.forms.fields.ChoiceField object at 0x117323080>)]) Form is False
In your view, you make a call to the CalendarSelectionForm constructor with request.POST as first positional argument. So that means that you call the __init__ function, and request.POST is passed as the calendars parameter.
You can fix this by constructing your form with named parameters. You furthermore will need to pass the same parameter to calendars as you did when you rendered the form with the GET request, since otherwise the choices do not per se match, and the user might have picked an option that is in that case not available during the POST request. Like:
if request.method == 'POST':
cal_sync_form = CalendarSelectionForm(calendars=my_calendars, data=request.POST)
# ...
with my_calendars the same value you pass when you constructed the form in the GET case.
My django form is invalid and so the .is_valid method never returns true. As a result, I am getting an "Expected HttpResponse but received None" type of error because my code never executes what is within the if-condition. I am wondering how to make my form valid. I am new to django so I am probably missing something obvious. Here is my code:
views.py
template_name1 = 'multiplication/detail.html'
template_name2 = 'multiplication/multiplied.html'
class myForm(forms.Form):
quantity1 = forms.IntegerField(required=False)
quantity2 = forms.IntegerField(required=False)
form = myForm()
def get(request):
return render(request,template_name1,{'form': form} )
def multiply_two_integers(x,y):
return x*y
def post(request):
if (form.is_valid()):
x = request.POST.get('quantity1')
y = request.POST.get('quantity2')
product = multiply_two_integers(x, y)
return render(request, template_name2, {'form': form, 'product':
product })
template_name1
<h1>Multiplication Function</h1>
<form action = "{% url 'multiplication:post' %}" method = "post">
{{ form.as_p }}
{% csrf_token %}
<input type = "submit" value ="Multiply">
<!--<button type="submit"> Multiply </button>-->
<h1>{{product}}</h1>
</form>
template_name2
<h1>{{product}}</h1>
urls/multiplication
from django.urls import path
from multiplication import views
app_name = 'multiplication'
urlpatterns = [
# /multiplication/
path('', views.get, name = 'get'),
path('multiplied', views.post, name='post')
]
This code is very strange. You seem to have a set of functional views, but are trying to randomly use some concepts from class-based views.
The reason why your form is not valid is because you never pass any data to it; an unbound form cannot be valid. You should not be instantiating the form outside of a view; you need to do it in the view, and when the request is a POST you should pass the POST data to it.
In function-based views you should not define separate functions for get and post. Combine them, as sown in the Django docs.
There is another point that you have missed about the error message; your reaction to it telling you that you have not returned a response if the form is invalid is to ask "why isn't it valid", but you should also do what it says and return a response in this case; the form will sometimes be actually invalid, and you should deal with this case.
Finally, to get the data from the form you should use form.cleaned_data, not request.POST.
def multiply_two_integers(x,y):
return x*y
def my_view(request):
if request.method == 'POST':
form = MyForm(request.POST)
if (form.is_valid()):
x = form.cleaned_data['quantity1']
y = form.cleaned_data['quantity2']
product = multiply_two_integers(x, y)
return render(request, template_name2, {'product': product })
else:
form = MyForm()
return render(request,template_name1,{'form': form} )
I'm trying to extend the flask-base project http://hack4impact.github.io/flask-base/templates/ . I have the following view functions:
#login_required
#main.route('/cities', methods=['GET', 'POST'])
def cities():
if request.method =='POST':
print(request.data)
redirect('/selected')
cities_list = []
recordset = Postings.query.all()
for r in recordset:
city = str(r.city)
elapsed_hours = round((time.time() - int(r.datetime)) / 3600, 1)
cities_list.append(str(r.city) + '-' + str(r.email) + '-' + str(elapsed_hours))
form = PostingSelectForm()
form.posting.choices = [(item, item) for item in cities_list]
return render_template("main/cities.html",
form = form)
#login_required
#main.route('/selected')
def selected():
return 'ddd'
I'm using a macro to generate a form as described in the docs above. The macro is called render_template and works normally to produce a form which I am able to submit. You can see the submitted info in the screenshot. However I am not able to capture the info in the lines:
print(request.data)
redirect('/selected')
and the redirect does not occur. When I look at the html of the wtf-form generated by the macro. it starts with;
<form action="" method="POST" enctype="" class="ui form
">
<div style="display:none;"><input id="csrf_token" name="csrf_token" type="hidden" value="1516882441##491001e55a57ceac4053b7937d21e61768f66d0b"></div>
So I'm wondering if the lack of an action is the problem here. I don't know what posting to "" does. Also if that is the problem how would I modify my form to include an action given that is generated by this macro. My forms code is:
class PostingSelectForm(Form):
posting = SelectField(
'posting',
choices=[('cpp', 'C++'), ('py', 'Python'), ('text', 'Plain Text')]
)
submit = SubmitField('Select')
I have a django 1.6.11 form (views.py):
def posneg_nlp(request):
sys_project_name = request.GET.get('project', 'graph') # here oll is ok, it can get correct project value
success = False
monitoring_words = ''
pos_features = ''
neg_features = ''
date_saved = datetime(2015, 7, 29)
print('posneg_nlp form')
print("posneg_nlp request.GET.get('sys_project_name', 'graph')", request.GET.get('project', 'graph'))
if request.method == 'POST':
posnegnlp_form = PosnegnlpForm(request.POST)
if posnegnlp_form.is_valid():
print('posneg_nlp form is_valid')
success = True
sys_project_name = sys_project_name
# here it cannot get project value, it replaced with default:
print("posneg_nlp form is_valid request.GET.get('sys_project_name', 'graph')", request.GET.get('project', 'graph'))
print("sys_project_name ", sys_project_name)
monitoring_words = posnegnlp_form.cleaned_data['monitoring_words']
pos_features = posnegnlp_form.cleaned_data['pos_features']
neg_features = posnegnlp_form.cleaned_data['neg_features']
print('pos_features:', pos_features, 'neg_features:', neg_features)
posneg_nlp_filter(sys_project_name, pos_features, neg_features, db_collection=Vkwallpost)
#get_likes_wallposts_by_owner_id(typeobject='post', owner_id=None, item_id=None, filter_posts='likes')
else:
posnegnlp_form = PosnegnlpForm()
success = False
ctx = {'posnegnlp_form': posnegnlp_form, 'sys_project_name': sys_project_name, 'monitoring_words': monitoring_words,
'pos_features': pos_features, 'neg_features': neg_features, 'success': success}
return render_to_response('choose_nlp_filter.html', ctx, context_instance = RequestContext(request))
This is the second form among two. From first form i pass a variable sys_project_name to this form via template:
<div class="rowSubmit">
<a style="outline: medium none;" hidefocus="true" href="{{ DOMAIN_URL }}/post/choose_nlp_filter/?project={{ sys_project_name }}" class="btn btn-right"><span class="gradient">К шагу 2. Выбор фильтров </span></a>
</div>
When i print current value of sys_project_name in form function posneg_nlp(request) above it shows correct value request.GET.get('project', 'graph') equal to graph2 (happens on form render).
But after that after if posnegnlp_form.is_valid(): it stops to see it and request.GET.get('project', 'graph') shows value in case it not found, equal to "graph".
So, how to pass variable and dont allow to rewrite it?
In the first case, the view is responding to an http GET request, so request.GET contains your project parameter. When the form is submitted, now the view is responsing to an http POST request, and request.POST contains the form data. In the latter case, if you want request.GET to still contain the 'project' parameter, then you can pass it via the form action parameter in your form tag:
form action="/some/url/?project={{ sys_project_name }}"