Flask/Jinja2 form submit button not working - flask

I've got a simple form where a user enters two dates. My input is getting passed correctly, but the Submit button isn't working. Here's my view:
# GLASS ------------------------------------------------------------------------
class NameForm(Form):
starts_on = StringField('Starts', validators=[Required()])
ends_on = StringField('Ends', validators=[Required()])
submit = SubmitField('Go')
#app.route('/glass/', methods = ['GET', 'POST'])
def glasses():
starts_on = None
ends_on = None
results = None
form = NameForm()
if form.validate_on_submit():
starts_on = form.starts_on.data
ends_on = form.ends_on.data
# SQL takes starts_on, and ends_on as inputs
results, start_date, end_date, companies_tracked = diagUserActs.userTime(starts_on, ends_on, diagUserActs.companies)
form.starts_on.data = ''
form.ends_on.data = ''
return render_template('glass.html', form = form, results = results)
And here's my template:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
<!--{% block title %}Glasses{% endblock %}-->
{% block content %}
<form class="form-inline" method="post" role="form">
{{ wtf.form_field(form.starts_on) }}
{{ wtf.form_field(form.ends_on) }}
{{ wtf.form_field(form.submit) }}
</form>
Oddly enough, this method below works, but I'd like to list the form elements individually so I've got more control regarding its presentation:
<form class="form-inline" method="post" role="form">
{% for field in form %}
{{ field.label }}
{{ field(placeholder="YYYY-MM-DD") }}
{% endfor %}
</form>

What I've done before is use something like this:
{% macro render_field(field, class='None') %}
<div class="pure-control-group">
{{ field.label(class_=class)|safe }}
{{ field(class_=class)|safe }}
{% if field.errors %}
<p class="errors">
{% for error in field.errors %}
<p>
{{ error }}
</p>
{% endfor %}
</p>
{% endif %}
</div>
{% endmacro %}
Then use it something like this:
{{ render_field(form.username) }}
Where form is something like this:
form = forms.Login(request.form)
It seems there is something wrong with the form here:
{{ wtf.form_field(form.starts_on) }}
I've never seen it used that way.

Related

Django QuerySet retuns empty queryset

I have not been able to tell why this model query returns an empty queryset...
Here are my models:
class Marks(models.Model):
klass = models.ForeignKey(Klass,on_delete=models.SET_NULL,null=True,blank=True)
stream = models.ForeignKey(Stream,on_delete=models.SET_NULL,null=True,blank=True)
mark = models.IntegerField()
class Klass(models.Model):
name = models.CharField(max_length=20)
The view.
def ResultsView(request):
query = request.GET.get('klass')
if query:
queryset = (Q(klass__name__icontains=query))
the_student = Marks.objects.filter(queryset).distinct()
all_results = {'the_student':the_student,'query':query}
else:
all_results = {}
return render(request,'exams.html',all_results )
The form template
<form action="{% url 'search_marks' %}" method="GET">
<div class="input-group">
<input class="" style="flex:50%" type="text" name="klass">
<button class="btn btn-primary" type="submit"></button>
</div>
</form>
The url
path('search_m',ResultsView,name='search_marks'),
I try getting the results here
{% for mark in the_student %}
{{ mark }}
{% endfor %}
When I print the_student from the view it gives <QuerySet []>
When I try queryset = (Q(mark__icontains=query)) brings an answer for the mark.
I only want a result for klass
I think you are using the whole queryset in your template.
Try
{% for mark in the_student %}
{{ mark.klass }}
{% endfor %}
the_Student is your response key but you use the_student.
the_student != the_Student
you just change the
{% for mark in the_student %}
{{ mark.klass }}
{% endfor %}
to
{% for mark in the_Student %}
{{ mark.klass }}
{% endfor %}

How to create and submit multiple instances of a form on a single page?

I want 3 instance of a URL input form so I can submit up to 3 different URLs.
forms.py
class AdditemForm(forms.Form):
url = forms.URLField(
label='Add Item',
widget=forms.URLInput(
attrs={
"class": "form-control",
}))
view.py
def ItemDetail(request, pk):
listitem = comparelist.objects.get(id=pk)
if request.method == 'POST':
form = AdditemForm(request.POST)
if form.is_valid():
url = form.cleaned_data.get("url")
items.objects.create(
link=url,
name=product_name,
price=price,
store=store,
)
return HttpResponseRedirect(request.path_info)
else:
form = AdditemForm()
template = 'itemdetail.html'
context = {
"comparelist": listitem,
"form": form,
}
return render(request, template, context)
I'm using a form snippet I found in a tutorial:
{% load widget_tweaks %}
<form method="post" class="form">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
So how do I get 3 of those forms on my page and be able to submit 3 different URLs?
I can only think of having to create 3 different form classes and paste the form snippet 3 times into the template. But that seems like a lot of unnecessary repetition.
Why "create 3 different form classes" ??? You can just create three instances of the same form.
paste the form snippet 3 times into the template
Ever heard about lists and loops ? You can put the three (or more) forms in a list and loop over it.
BUT that's actually not the best solution here - Django has Formsets for this use case.

Django FormWizard dynamic forms

I am trying to create a FormWizard to add multiple instances of a model at once. The second page is dynamic, based on the number to be added, and creates a single "serial number" field - the differentiating factor between all the instances.
I'm getting the first page of the wizard fine, but the second page - the dynamic one - is giving me this Validation Error:
[u'ManagementForm data is missing or has been tampered.']
All the searching I've done points to a formset issue, which I'm not using. What have I done wrong?
forms.py
class CarrierWizardForm1(forms.Form):
part_numbers = forms.ModelChoiceField(queryset=PartNumber.objects.all())
expiry_date = forms.DateField()
qty_at_new = forms.IntegerField()
unit_cost = forms.DecimalField(max_digits=10, min_value=0, decimal_places=3)
cost_currency = forms.ChoiceField(choices=CURRENCY_CHOICES)
class CarrierWizardForm2(forms.Form):
def __init__(self, *args, **kwargs):
qty = kwargs.pop('qty')
super(CarrierWizardForm2,self).__init__(*args,**kwargs)
for i in qty:
self.fields['serial_%s' % i] = forms.CharField(max_length=45)
The defs in CarrierWizardForm2 is a fairly common idiom that is noted all over the web as a solution to this problem, including by Jacobian Nor is their anything crazy in urls
urls.py
carrier_wizard_forms = [CarrierWizardForm1, CarrierWizardForm2]
...
url(r'^carrier/add/$', views.CarrierCreateWizard.as_view(carrier_wizard_forms)),
My views are relatively complex, but nothing outrageous. Note there are some fields that aren't in the forms - they are filled with context data (user, creation date, etc)
views.py
TEMPLATES = {"0": "inventory/carrier_wizard_form1.html",
"1": "inventory/carrier_wizard_form2.html"}
class CarrierCreateWizard(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
''' Get the qty from form 1 to indicate how many fields
form2 needs for serial numbers
'''
def get_form_initial(self, step):
current_step = self.storage.current_step
if current_step == 'step1':
prev_data = self.storage.get_step_data('step0')
return self.initial_dict.get(step, {'qty': qty})
return self.initial_dict.get(step, {})
def done(self, form_list, **kwargs):
details = form_list[0]
list_of_serial_nos = form_list[1]
for serial_name, serial in list_of_serial_nos.cleaned_data.items():
carrier = Carrier()
carrier.part_numbers = details.cleaned_data['part_numbers']
carrier.creation_date = datetime.datetime.today()
carrier.expiry_date = details.cleaned_data['expiry_date']
carrier.qty_at_new = 1
carrier.qty_current = 1
carrier.serial = serial
carrier.unit_cost = details.cleaned_data['unit_cost']
carrier.cost_currency = details.cleaned_data['cost_currency']
carrier.user = self.request.user
carrier.save()
My second template is bland, although you can see three unsuccessful attempts to rectify this issue.
inventory/carrier_wizard_form2.html
{% extends "base.html" %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% csrf_token %}
{# Attempt 3 #}
{{ formset }}
{# Attempt 2 {{ form.management_form }}
{% for f in form %}
{{ f.as_p }}
{% endfor %}
#}
{# Attempt 1 {{ form }} #}
<input type=submit>
</form>
{% endblock %}
EDIT
*As requested, both of my templates*
inventory/carrier_wizard_form1.html
{% extends "base.html" %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% csrf_token %}
{{ wizard.form.as_p }}
<input type=submit>
</form>
{% endblock %}
templates/inventory/carrier_wizard_form2.html
{% extends "base.html" %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% csrf_token %}
<table>
{{ wizard.form }}
{#
{{ wizard.management_form }}
{% if wizard.form.forms %}..
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}.
{% endif %} #}
</table>
<input type=submit>
</form>
{% endblock %}
Your template is not correct, use {{ wizard.management_form }} to add wizard management related stuff and use {{ wizard.form }} for forms.
From the reference doc the template is like:
{% extends "base.html" %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% csrf_token %}
{{ wizard.management_form }} {#add wizard management data #}
{% if wizard.form.forms %} {# if form is formset #}
{{ wizard.form.management_form }} {#formset's management data #}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }} {#for normal form #}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>

django form error messages not showing

So I have my view:
def home_page(request):
form = UsersForm()
if request.method == "POST":
form = UsersForm(request.POST)
if form.is_valid():
form.save()
c = {}
c.update(csrf(request))
c.update({'form':form})
return render_to_response('home_page.html', c)
my forms.py:
class UsersForm(forms.ModelForm):
class Meta:
model = Users
widgets = {'password':forms.PasswordInput()}
def __init__(self, *args, **kwargs):
super( UsersForm, self ).__init__(*args, **kwargs)
self.fields[ 'first_name' ].widget.attrs[ 'placeholder' ]="First Name"
self.fields[ 'last_name' ].widget.attrs[ 'placeholder' ]="Last Name"
self.fields[ 'password' ].widget.attrs[ 'placeholder' ]="Password"
and my template:
<html>
<body>
<form method="post" action="">{% csrf_token %}
{{ form.first_name }} {{form.last_name }} <br>
{{ form.password }} <br>
<input type="submit" value="Submit Form"/>
</form>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<p> {{ errors }} </p>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<p> {{ error }} </p>
{% endfor %}
{% endif %}
</body>
</html>
Now, keep in mind that before I split the form field, my form just looked like this:
<form method="post" action="">{% csrf_token %}
{{ form }}
<input type="submit" value="Submit Form"/>
</form>
and if the form had a problem (like if one of the fields was missing) it would automatically give an error message. After I split up the form fields in the template (made {{ form.first_name }}, {{ form.last_name }} and {{ form.password }} their own section) it stopped automatically giving error messages. Is this normal?
But the main problem is, how come my {{ if form.errors }} statement is not working / displaying error messages if there are error messages? For example, if I purposely not fill out a field in the form and I click submit, the database does not get updates (which is a good thing) but it does not give any error messages. Any idea why?
I also tried remove the {{ forms.non_field_errors }} and tried to return just field errors like so:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<p> {{ errors }} </p>
{% endfor %}
{% endfor %}
{% endif %}
but it still doesn't work.
I found the mistake (typo).
The snippet should be:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<p> {{ error }} </p>
{% endfor %}
{% endfor %}
{% endif %}
I had errors instead of error.
you have to send your form context again if is_valid() isn't true,
if form.is_valid():
return redirect('/user/contact/')
else:
return render(request, 'users/contact.html', context={'form': form})
because your errors will display in your form
else: it will return ValueError
Add this snippets in views.py like this
if request.method == "POST":
fm = UserRegsitrationForm(request.POST)
if fm.is_valid():
fm.save()
else:
fm = UserRegsitrationForm()
context = {'fm':fm}
return render(request,'registration.html',context)
The error capture could very well have been done with:
{% for field in form %}
{{ field.errors }}
{% endfor %}

django - form has no errors but form.is_valid() doesn't validate

I have a form that for some reason it it doesn't throw any errors (if user adds data in the text field) but form.is_valid() doesn't validate. Any ideas?
forms.py:
class MyForm(forms.Form):
title = forms.CharField(widget=forms.TextInput(attrs={'class':'titleField'))
mytemplate.html
<form action="" method="post" name="form">{% csrf_token %}
{{ form.title.errors }}
{{ form.title }}
<input type="submit" name='submit_button' value="Post" />
</form>
views.py:
if 'submit_button' in request.POST:
form = MyForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
title = cd['title']
g = MyData(title='title')
g.save()
else:
form = MyForm()
From your template, add the following:
{{ form.errors }}
{{ form.non_field_errors }}
Do you see any errors from the above?
You can also print (or log) error at back end too, Similarly use this:
Like, to print error:
print(form.errors)
I'm using this block with bootstrap
{% if form.errors %}
<div class="alert alert-danger" role="alert">
{% for field, errors in form.errors.items %}
{% for error in errors %}
<b>{{ field }}</b>: {{ error }}
{% endfor %}
{% endfor %}
</div>
{% endif %}