Flask form not getting validated - flask

My flask form is not getting validated.
#admin_blueprints.route('/ManageMovies',methods=['GET', 'POST'])
def ManageMovie():
form = SetShowForm(request.form)
if request.method == 'POST' and form.validate():
print(form.movie.data)
return redirect(url_for('admin.AdminHome'))
engine = create_engine('mssql+pyodbc://DESKTOP-6UNRAN0/movie_f?driver=SQL Server?
Trusted_Connection=yes')
form.movie.choices = [(movie.m_id, movie.m_name)for movie in (engine.execute('select * from
MovieMaster'))]
form.show_time.choices = [(time.s_id, time.s_time) for time in (engine.execute('select * from
ShowTime'))]
return render_template('manage_movies.html',form=form)
my template code is
{% extends "master.html" %}
{% block content %}
<form method="POST">
{{ form.hidden_tag() }}
{{form.movie.label}}{{form.movie(class="form-control")}}
<br>
{{ form.show_time.label }} {{form.show_time(class="form-control")}}
<br>
{{form.price.label}} {{ form.price(class="form-control") }}
<br>
{{form.submit(class="btn btn-success")}}
</form>
{% endblock %}
my flask form
class SetShowForm(FlaskForm):
movie = SelectField('Movie Name', choices=[])
show_time = SelectField('Set Show Time',choices=[])
price = IntegerField('Price')
submit = SubmitField("Set")
Once I click on my submit button, the same page gets rendered again instead of entering my (if request.method == 'POST' and form.validate():) statement and printing the data. I have no idea what is going wrong. I am filling all the fields. Are there any rule for form validation.

I believe you need to use:
if form.validate_on_submit():
And you don't need to check for "POST" because validate_on_submit does that too.

Try it
#admin_blueprints.route('/ManageMovies',methods=['GET', 'POST'])
def ManageMovie():
form = SetShowForm()
if form.validate_on_submit():
print(form.movie.data)
return redirect(url_for('admin.AdminHome'))
return render_template('manage_movies.html',form=form)
And set choices values in setShowForm() directly

Related

Reverse for 'update_laptop' with arguments '('',)' not found. 1 pattern(s) tried: ['update_laptop/(?P<laptop_id>[^/]+)/$']

I am building an Inventory system and want to add update functionality. but unfortunately, it is not working.
Please help me with this code error.
views.py:
def update_laptop(request, laptop_id): # function for updation of laptops.
update = Laptop.objects.get(pk=laptop_id)
if request.method == 'POST':
form = LaptopForm(request.POST, instance=update)
if form.is_valid():
form.save()
return redirect('laptop')
form = LaptopForm(request.POST)
context = {
'forms': form, 'header': 'Laptop'
}
return render(request, 'device/update_laptop.html', context)
update_laptop.html:
{% extends 'device/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<form action="" method="POST">
{% csrf_token %}
<h3>Add {{ header }}:</h3>
{{ forms|crispy }}
Update
</form>
</div>
{% endblock %}
urls.py:
path('update_laptop/<str:laptop_id>/', views.update_laptop, name='update_laptop')
The forms has no .id, hence that will not work. You can pass the laptop_id to the view, or obtain this from the form.instance.id.
The construction of the form is however wrong, since in the case of a GET request, you should not pass request.POST, but you can nevertheless pass the instance=update.
from django.shortcuts import get_object_or_404
def update_laptop(request, laptop_id):
laptop = get_object_or_404(Laptop, pk=laptop_id)
if request.method == 'POST':
form = LaptopForm(request.POST, instance=laptop)
if form.is_valid():
form.save()
return redirect('laptop')
form = LaptopForm(instance=laptop)
context = {
'forms': form,
'header': 'Laptop'
}
return render(request, 'device/update_laptop.html', context)
In the template, you should make a submit button. By using a link, you will make a GET request, and thus not update the object:
<form action="{% url 'update_laptop' forms.instance.id %}" method="POST">
{% csrf_token %}
<h3>Add {{ header }}:</h3>
{{ forms|crispy }}
<button "type="submit">Update</button>
</form>
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.

Queryset object in Django form not iterable

I'm trying to get the form to create the fields based on what exam page the user is on. In the error page, all local variables have the correct value for form and view, but I keep getting ExamQuestion object not iterable and an error at line 0 of the template. It also highlights the render() at line 44 in the view as the source of the problem. If I change line 28 from exam__name=exam_name to exam__name="exam_name", basically turning the variable into a str, the page runs but no data is passed.
In the error console choice_list shows querysets as individual list items as it should for forms.py
How do I make the object ExamQuestion iterable? I've been stumped for a week now. I've written a hundred ways at this point.
I know it's listing questions instead of answers for the questions, I'm just trying to get it to load ANY queryset and freaking run at this point.
view
def exampage(request, exam_name):
exams = Exam.objects.all()
questionlist = ExamQuestion.objects.filter(exam__name=exam_name)
choicelist = ExamChoice.objects.filter(question__exam__name=exam_name)
form = ExamTest(request.POST, exam_name=exam_name)
if request.method == "POST":
if form.is_valid():
#form.save()
#choice = form.cleaned_data.get('choice')
return redirect('exampage.html')
return render(request, 'exams/exampage.html', {'exams': exams,'questionlist': questionlist, 'exam_name': exam_name, 'choicelist': choicelist, 'form': form, 'choice': choice})
else:
form = ExamTest(exam_name=exam_name)
return render(request, 'exams/exampage.html', {'exams': exams,'questionlist': questionlist, 'exam_name': exam_name, 'choicelist': choicelist, 'form': form})
form
class ExamTest(forms.Form):
def __init__(self, *args, **kwargs):
exam_name = kwargs.pop('exam_name')
super(ExamTest, self).__init__(*args, **kwargs)
#choice_list = [x for x in ExamQuestion.objects.filter(exam__name="dcjs01")]
#choice_list = []
x = ExamQuestion.objects.filter(exam__name=exam_name)
#for q in x:
# choice_list.append(q)
self.fields["choices"] = forms.ChoiceField(choices=x, label="testlabel")
template
{% extends 'portal/base.html' %}
{% block content %}
<h1>{{ exam_name }} Page</h1>
{{ exam_id }}
<hr>
{% for exam in exams %}
<li>{{ exam }}</li>
{% endfor %}
<h1>! {{ questionlist }} !</h1>
<form method="post" action="#">
{% csrf_token %}
formtest{{ form }}
<button type="submit"> finish test </button>
</form>
{% endblock %}
The first part of the question is - you getting the ExamQuestion not iterable error:
here I think is the problem, that you, in the Form init function pass the Queryset (objects.filter(xxx)), but not the .all() which will select it.
the second thought is - would'n it be better to pass the questions as a parameter to the Form, as you previously selected all the question for this particular exam?
figured it out. choices=x needs to be a tuple
self.fields['name'] = forms.ChoiceField(choices=tuple([(name, name) for name in x]))

Django Admin Action using intermediate page

I have a model with a lot of fields. I only have a few fields I that I want to be required. So instead of the change list super long, I want to have a short change list then have admin actions that can give predefined subsets of the fields.
The initial action takes me to the correct page but when I submit the form it returns me to whatever page I designate, but doesn't update the fields. I am okay with tearing this down starting over again if needed. I think what I really need to know, what do I put in the action="" portion of the html to have the recursion work properly?
I am using django 1.7. I have to obfuscate a lot of my fields as a cya thing since I am working in a heavily information secure field.
Here is my admin.py
class CredentialAdmin(admin.ModelAdmin):
fields = ['reservedBy','reserveto']
list_display = ['reservedBy','reserveto']
class reserveToFormAdmin(forms.Form):
reservedBy = forms.CharField(widget=forms.Textarea, max_length=50)
reserveto = forms.DateTimeField(widget=forms.DateTimeInput)
def reserveCred(self, request, queryset):
form = None
plural = ''
if 'submit' in request.POST:
form = self.reserveToFormAdmin(request.POST)
for f in form.fields:
print f
print form.is_valid()
print form.errors
if form.is_valid():
reservetos = form.cleaned_data['reserveto']
reservedBys = form.cleaned_data['reservedBy']
print "hello"
count = 0
for cred in queryset:
cred.reserveto = reservetos
cred.reservedBy = reservedByss
cred.save()
count += 1
if count != 1:
plural = 's'
self.message_user(request, "Successfully reserved %s cred%s." % (count, plural))
return HttpResponseRedirect(request.get_full_path(),c)
if not form:
form = self.reserveToFormAdmin(initial={'_selected_action' : request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})
return render(request,'admin/reserveCreds.html',{'creds':queryset, 'form':form, 'path':request.get_full_path()})
reserveCred.short_description = "Reserve Selected Creds"
actions = [check_out_a_cred,check_in_a_cred,audit_creds,CompareAudits,reserveCred]
reserveCreds.html
{% extends "admin/base_site.html" %}
{% block content %}
<p>How long and which department to reserver creds:</p>
<form action="{{ path }}" method="post">{% csrf_token %}
{{ form }}
<input type="submit" name="submit" value="submit" />
<input type="button" value = "Cancel" />
</form>
<h2> reserving: </h2>
<ul>
{% for cred in creds %}
<li> {{ cred.userid }} </li>
{% endfor %}
</ul>
{% endblock %}

ChoiceField form is not valid and returns "too many values to unpack"

So, I am having this form where I display a list of all my app models in a drop-down list and expect from the user to choose one so as to display its fields. Below is my form and the models() method, which creates the list of models to be passed as argument to my ChoiceField.
*forms.py*
class dbForm(forms.Form):
model_classes_field = forms.ChoiceField(choices=models(), required=True,)
def models():
apps = get_app('Directories')
m_id = 0
for model in get_models(apps):
m_id += 1
model_classes.append({
'model_name': model._meta.verbose_name,
'model_id': m_id,
'model_table': model._meta.db_table,
'model_object': model.objects.all()
})
return model_classes
In my views.py I tried handling the POST data but unfortunately for some reason the form was not valid and I couldn't manipulate any data. Furthermore form.errors does not display anything at all.
*views.py*
def index(request):
if request.method == 'POST': # If the form has been submitted...
form = dbForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
model_classes_field = form.cleaned_data['model_classes_field']
return HttpResponseRedirect('/list/') # Redirect after POST
else:
print "form: ", form.errors
else:
form = dbForm() # An unbound form
print "form: ", form.errors
print "not valid form"
return render(request, 'Directories/index.html', {
'form': form,
})
Furthermore, in the template whenever i try to submit the form it returns an error message "too many values to unpack" and does not redirect me to the next template (list.html).
*index.html*
{% block content%}
<div id="content" align="center">
<h2> Welcome! this is Directories app! </h2>
<form action="" method="post">{% csrf_token %}
{{ form.model_classes_field.errors }}
<label for="id_model_classes_field">Choose from one of the existing tables:</label>
<select id="id_model_classes_field" name="model_classes_field">
{% for choice in form.fields.model_classes_field.choices %}
<option name="m_id" value="{{ choice.model_table }}">{{choice.model_id}}: {{choice.model_name}}</option>
{% endfor %}
</select> <br />
<input type="submit" value="Change" name="_change" />
</form>
</div>
<div id="bottom">
</div>
{% endblock %}
The only workaround i found on this is to fill the form action with the template to be redirected at (i.e. action = "list") instead of doing it in the views with return HttpResponseRedirect('/list/') . However, I believe that this does not solve the issue since still the form is not valid and i cannot process data with form.cleaned_data. It's peculiar though that the post data is sent even though the form is not valid.
*
EDIT: Solution
I changed my models() method as such:
def models():
apps = get_app('Directories')
for model in get_models(apps):
model_classes.append( (model._meta.verbose_name, model._meta.db_table), )
return model_classes
so I included a tuple as instructed by #Rohan and after making a slight alteration to my index.html:
...
{% for choice in form.fields.model_classes_field.choices %}
<option name="m_id" value="{{choice.0}}">{{choice.0}}</option>
{% endfor %}
...
form is valid and can now process my data.
*
Value of choices should be list/tuple containing items with exactly 2 elements. But you are creating list of dicts which might be causing the issue.
for model in get_models(apps):
m_id += 1
model_classes.append({
'model_name': model._meta.verbose_name,
'model_id': m_id,
'model_table': model._meta.db_table,
'model_object': model.objects.all()
})
So you may want to update models() method to return appropriate list/tuple.

Displaying None Field Errors in Django Template

I want to display my non_field_erors in my template. So far, I can display all kind of errors of my forms with:
-> base.html
{% if form.errors %}
{% for field in form %}
{% if field.errors %}
<div class="ui-state-error ui-corner-all notification" >
<p>
<span class="ui-icon ui-icon-alert"></span>
{{ field.label_tag }}:{{ field.errors|striptags }}
<a class="hide" onClick="hideBar(this)">hide</a>
</p>
</div>
{% endif %}
{% endfor%}
{% endif %}
AND
{{ form.non_field_errors }}
I've added a new form which has only an IntegerField:
class MerchantForm(forms.ModelForm):
price = forms.IntegerField(widget=forms.TextInput(attrs={'class':'small'}))
def clean_price(self):
price = self.cleaned_data.get('price')
if price == 120:
raise forms.ValidationError('error blah.')
return price
When I post price as 120, I don't get any validation errors in my page.
And my view is:
def bid(request,product_slug):
.
.
form = MerchantForm()
context = RequestContext(request,{
'form':form,
....
})
if request.method == 'POST':
form = MerchantForm(request.POST)
if form.is_valid():
return HttpResponse('ok')
# else:
# return HttpResponse(form.errors.get('__all__'))
return render_to_response('bid.html',context_instance=context)
I can retrieve the error with commented lines but I don't want to do that in views.py. Any ideas ?
Oh dear.
First of all, why are you asking about non_field_errors when the code snippet you post clearly has the error as being raised in clean_price, and therefore is associated with ths price field?
Secondly, your view code is upside down. You create an empty form instance, and add it to the context. Then you create another form instance, bound to the POST data, but don't put it into the context. So the template never sees the bound form, so naturally you never see any validation errors in the template.