I am using Django Form View to split a large, single-page form into a multi-page form with separate templates for each one. I followed the documentation and other online examples, and most everything is going well.
However, the problem is that I have required fields in the form and they are failing validation because, as it turns out, the data is not being passed back to Django (as was verified by overriding 'is_valid()' and printing the form data, as well as printing {{ wizard.form.errors }} in my templates). It may be worth noting that the form worked fine before I split it up.
Below is a shortened version of the relevant code. If anyone has some pointers that would be great. I am no expert at this and the original code was not written by me, so I'll answer any questions as best I can. Thanks!:
VIEWS.PY
FORMS = [("venue", RegisterBusinessFormVenue),
("manager", RegisterBusinessFormManager),
("extras", RegisterBusinessFormExtras)]
TEMPLATES = {"venue": "registrationVenue.html",
"manager": "registrationManager.html",
"extras": "registrationExtras.html"}
class RegisterBusinessView(SessionWizardView):
file_storage = FileSystemStorage(location=os.path.join('/var/www/', 'logos'))
def get_template_names(self):
return TEMPLATES[self.steps.current]
def done(self, form_list, **kwargs):
return HttpResponseRedirect(reverse_lazy('submission_page_view'))
MODELS.PY
class RegisterBusinessFormVenue(forms.Form):
venue_name = forms.CharField(label='Venue Name', max_length=128)
class RegisterBusinessFormManager(forms.Form):
manager_first_name = forms.CharField(label='First Name', max_length=255)
class RegisterBusinessFormExtras(forms.Form):
website = forms.URLField(label="Website", required=False)
URLS.PY
url(r'^register/', RegisterBusinessView.as_view(FORMS), name='register_business_view')
TEMPLATE
{% extends "base.html" %}
{% load staticfiles %}
{% block stylesheet %}
<link rel="stylesheet" href="{% static 'css/registration.css' %}">
{% endblock stylesheet %}
{% block content %}
<div class="page-header">
<h1>Register your business</h1>
</div>
<form class="form-horizontal" role="form" action="" method="POST">{% csrf_token %}
{{ wizard.management_form }}
{{ wizard.form.errors}}
{{ wizard.form.non_field_errors}}
<legend>Event Venue Information</legend>
<div class="form-group required {% if wizard.form.venue_name.errors %}has-error{% endif %}">
<label for="inputVenueName" class="col-sm-3 control-label">{{ wizard.form.venue_name.label }}</label>
<div class="col-sm-9">
<input type="text" class="form-control"
name="{{ wizard.form.venue_name.name }}"
id="inputVenueName"
{% if wizard.form.venue_name.value %}value="{{ wizard.form.venue_name.value }}"{% endif %}
placeholder="Venue name where events are held"
spellcheck="true">
</div>
</div>
<div class="register-btn-block">
<button type="submit">Register</button>
</div>
</form>
{% endblock content %}
I answered my own question. It was a dumb mistake on my part: I wasn't using the wizard provided id's and name's for my html markup. In my template above where I have the 'label for' and 'id' attributes, they should be populated with the value '{{ wizard.form.venue_name.id_for_label }}'. For the 'name' attribute, it should be populated with '{{ wizard.form.venue_name.html_name }}'.
The pre-defined values that can be used are found here. After making these changes, then the form data was properly submitted to the server.
Related
I am using django-easy-select2 to handle the entering of data into several manytomanyfields within a model - titled Engagement.
I am using bootstrap and crispy forms to render the Engagement form to HTML.
The rendering is broadly working as expected/required. However, the size of form fields for manytomany data are initially very small and require data to the selected/entered, before they expand. Once data is entered the fields do expand. But, I would like these fields to initially render as the size set by bootstrap.
For example, I've set bootstrap as col-6, but the initial render of the manytomany is only col-1 or even less. When data is entered that field will expand up to col-6 and no further, which good, but I would like the field to start at col-6, even with no data.
Relevant code is below.
engagements.view:
class EngagementCreateView(CreateView):
model = Engagement
form_class = select2_modelform(Engagement, attrs={'width': 'auto'}) # this sets the widths of the field
template_name = "engagements/engagement_create.html"
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
create engagement template
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h4>{% if form.instance.pk %}Edit engagement{% else %}Create new engagement{% endif%}</h4>
<div class="form-group">
<form method="post" novalidate>
{% csrf_token %}
<div class="row mt-1">
<div class="col-6"> # I'm rendering the width of fields here
{{ form.date|as_crispy_field }}
{{ form.projects|as_crispy_field }}
{{ form.stakeholders|as_crispy_field }}
{{ form.ppdds|as_crispy_field }}
</div>
<div class="col-6">
{{ form.follow_up_date|as_crispy_field }}
{{ form.engagement_types|as_crispy_field }}
{{ form.engagement_workstreams|as_crispy_field }}
</div>
</div>
<div class="row mt-1">
<div class="col-lg">
{{ form.summary|as_crispy_field }}
</div>
</div>
<br>
<input class="btn btn-primary" type="submit"
value="{% if form.instance.pk %}Save{% else %}Create{% endif%}">
<a class="btn btn-primary" href="../">Cancel</a></p>
</form>
</div>
{% endblock %}
I think the most relevant part of the django-easy_select2 documentation is here https://django-easy-select2.readthedocs.io/en/latest/usage.html.
I have a the following code for a Form that I have in my Flask application using Wtforms. I use FieldList to use two fields for one part.
class A(Form)
additional = FieldList(FormField(Additional), 'Additional', min_entries=1)
submit = SubmitField('Submit')
class Additional(Form):
choices = [('Funding Mechanism', 'Funding Mechanism'), ('Study Section Name', 'Study Section Name')]
critera = SelectField('Additional Criteria', choices=choices)
input = StringField()
The template uses wtf.quick_form:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Grants - Find Grant{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Specify</h1>
</div>
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
Currently the forms render in a squished and overlapping way like so:
How can I change the code so that it is formated in one line like below? It is a screenshot of #Niklas in Stockholm 's form from his question.
Thank you!
Since your form class A is calling class Additional as a FormField and only adding submit to the field, i added the submit button the Additional form itself and then called it in the view.
In the template, use
{{ wtf.quick_form(form, form_type="inline") }}
It outputs the page like this:
The form_type argument adds the .form-inline to the class attribute.
This is just a hack, surely your form will have more inputs than this, for that, you'll be writing the whole form template yourself.
The issue is that {{ wtf.quick_form(form) }} is calling wtf.form_field() on your FieldList additional in A instead of calling it on additional's subfields. Because of this, I don't think you will be able to use wtf.quick_form() on your particular form.
Instead, try templating your form like this:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Grants - Find Grant{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Specify</h1>
</div>
<div class="col-md-4">
<form class="form form-horizontal" method="post" role="form">
{{ form.hidden_tag() }}
{{ wtf.form_errors(form, hiddens="only") }}
{% for subfield in form.additional %}
{{ wtf.form_field(subfield) }}
{% endfor %}
{{ wtf.form_field(form.submit) }}
</form>
</div>
{% endblock %}
You can read more about wtf.form_field() on the Flask-Bootstrap documentation site.
I'm doing django-contrib-comment's custom comment app to my django app. At long last i achieved my comment app that has image field, and it shows in template of course. But here is the thing, When i'm trying to post comment with image, it does not saving image file, and says empty(This field is required). Can anyone help me to figure it out. Here is some code snippets.
models.py
class CommentWithPic(Comment):
image = models.ImageField(upload_to="comments/%Y/%m/%d/", null=True, blank=True)
forms.py
class CommentFormWithPic(CommentForm):
image = forms.ImageField()
def get_comment_model(self):
return CommentWithPic
def get_comment_create_data(self):
data = super(CommentFormWithPic, self).get_comment_create_data()
data['image'] = self.cleaned_data['image']
return data
post_with_comment.html
{% render_comment_list for adi %}
{% get_comment_form for adi as form %}
<form action="{% comment_form_target %}" method="post">
{% csrf_token %}
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.errors %}{{ field.errors }}{% endif %}
{{ field.label }}
{{ field }}
{% endif %}
{% endfor %}
<input type="hidden" value="{% url 'ad' adi.id %}"/>
<input type="submit" value="comment"/>
</form>
You need to declare your form like the following (notice the enctype attribute) when dealing with `ImageField
<form enctype="multipart/form-data" action="{% comment_form_target %}" method="post">\
to bind uploads to a form:
Dealing with forms that have FileField and ImageField fields is a little more complicated than a normal form.
Firstly, in order to upload files, you’ll need to make sure that your element correctly defines the enctype as "multipart/form-data"
You also need to make the image optional in the form:
class CommentFormWithPic(CommentForm):
image = forms.ImageField(required=False)
...
Below is my form code :
class FMessage(forms.Form):
From = forms.CharField()
To = forms.CharField()
Subject = forms.CharField()
Message = forms.CharField()
and this is my html code:
<form method='POST' action='.'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='submit'>
</form>
The code works fine by displaying forms and has not any issue in functionality, but now I need to wrap my form fields in html by a div like this:
<div id='mydiv'>
<input ... />
<div>
How can I fix it?
Seems like you do not really want to use the inbuilt <p> or <table> wrapped forms and rather want to display the fields wrapped within a <div>'s. You can simply iterate over fields in the form as follows.
{% if form %}
<!-- Form Errors -->
{% if form.errors %}
<ul class="errors">
{% for error in form.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<!-- Display Form -->
<form>
{% csrf_token %}
{% for field in form %}
<div class="mydiv">
<label class="mylabel">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
</form>
{% endif %}
Dont render the form by using form.as_p. You need to show each field of the form, for example, by using form.to. By using this way, you can wrap the field 'to' into a div
<div>{{ form.To}} </div>
For more detail, view this link
I'm creating a web app with django 1.2.4.
I am using contrib.auth.views.login, I have followed every step but it seems I have forgotten something cause I don't see the login form. Here is my folder structure:
/templates/
base.html
/myapp/
object_list.html
...
/registration/
login.html
...and here is my login.html:
{% extends "base.html" %}
{% block mylogin %}
<div class="horizontal">
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form action="{% url django.contrib.auth.views.login %}" method="post">
{% csrf_token %}
<div class="login_box">
<div class="login_text">{{ form.username.label_tag }}</div><div class="login_input">{{ form.username }}</div>
<div class="password_text">{{ form.password.label_tag }}</div><div class="password_input">{{ form.password }}</div>
<input id="button_login" type="submit" value="" />
</div>
</form>
</div>
{% endblock %}
...and in my base.html I have:
<div id="some_div">
{% block mylogin %} {% endblock %}
</div>
I have a basestyle.css included in base.html and the other templates inherit correctly too... it seems to be a block problem...
Any solution??
Thnak you
Instead of inserting of a block I used the include tag in base.html, just like this:
{% include "registration/login.html" %}
If you’d prefer not to call default (django provided) template registration/login.html, you can pass the template_name parameter via the extra arguments to the view in your URLconf.
For example, this URLconf line would use myapp/login.html instead:
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),
Reference : Django official documentation
It solves my problem. Hope this works for others.