How would to show form validation errors with django single fields? - django

I've to put in the fields of the form individually because for me its a little easier to style, my issue is that I can't seem to get it to display the error messages on validation. The form validates correctly, it just doesnt show what errors I get when I do get an error, instead it just doesnt submit. How can I fix this?
Template:
<form action="#" method="post"> {%csrf_token%} {{form.management_form}}
{%for f in form%}
{{ f.non_field_errors }}
<div class="row">
<div class="medium-3 columns ">
<label> First Name
{{ member_fname.errors }}
{{f.member_fname}}
</label>
</div>
<div class="medium-3 columns ">
<label> Last Name
{{ member_lname.errors }}
{{f.member_lname}}
</label>
</div>
<div class="medium-3 columns ">
<label> Email
{{ member_email.errors }}
{{f.member_email}}
</label>
</div>
<div class="medium-3 columns ">
<label> Phone #
{{ member_phone.errors }}
{{f.member_phone}}
</label>
</div>
</div>
<hr/>
{%endfor%}
<div class="row">
<div class="small-3 columns small-centered">
<button type="submit" class="button medium radius"> submit</button>
</div>
</div>
</div>
</form>

Syntax for rendering validation errors:
{{ form.fieldname.errors }}
This will show validation errors in a list format and if you want to render them as text then use:
{{ form.fieldname.errors.as_text }}

Related

How to return form field errors to template rendered in a different django view

I have a django bootstrap 4 template (wordcloud.html) that contains a form. The form was originally created as raw html within wordcloud.html, and the view for that template populates the fields. The form (create_wordcloud_form) uses post to send the data to a different view (create_wordcloud_view.py). The original developer didn't use django's built in template/form/view structure, so there is no form.py nor a form template.
The issue I need to address is validating the form. It has to be server-side validation, as one of the fields needs to be tested against one of the databases to prevent duplicate fields.
Do I need to refactor the whole mess into the standard django template/form/view idiom using crispy-forms, or is there a way to use what I already have and return some error messages from the view that processes the form data?
The code for validating the fields is easy. I am not sure how to structure the return statement in the event there are field errors, since wordcloud.html is rendered in a different view.
create_wordcloud_view:
#method_decorator(login_required, name='post')
class CreateWordCloud(View):
def post(self, request):
logger.debug("CreateWordCloud START")
q_dict = request.POST
logger.debug("q_dict=%s" % q_dict)
sources = []
filters = {}
cloud_name = None
for key in q_dict:
logger.debug("key=%s" % key)
if key == 'csrfmiddlewaretoken':
continue
if key in ["Titles", "Descriptions", "Comments", "Translations", "Text"]:
sources.append(key)
elif key == 'wordcloud_name':
cloud_name = q_dict['wordcloud_name']
else:
values = q_dict.getlist(key)
if len(values) == 1:
filters[key] = values[0]
else:
filters[key] = values
# Need to add field validation here
# 1. Must have at least one source
# 2. wordcloud_name must not be in the table of wordclouds
# 3. Alert user that no words were found for the combination of sources
# and filters selected
from wordcloud.tasks import create_wordcloud_task_3
create_wordcloud_task_3(None, cloud_name, sources, filters=filters)
# If the form data is valid and more than a few words are returned from
# create_wordcloud_task_3, then redirect to wordcloud.html
return redirect("/memorabilia/wordcloud.html", permanent=False)
# If form is invalid or no words returned from create_wordcloud_task_3,
# return to wordcloud.html with original data and appropriate field error
# messages.
return ????
create_wordcloud_form (a snippet from the wordcloud.html template):
<div id="wordcloud_form" style="display: none;">
<form action="/wordcloud/ajax/create_wordcloud/" class="was-validated" method="post">{% csrf_token %}
<div class="form-row">
<div class="col-md-12">
<p>First, select the source of words:</p>
</div>
</div>
<div class="form-row">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="source_text" name="Text">
<label class="form-check-label" for="source_text">Text</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="source_translation" name="Translations">
<label class="form-check-label" for="source_translation">Translations</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="source_titles" name="Titles">
<label class="form-check-label" for="source_titles">Titles</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="source_descriptions" name="Descriptions">
<label class="form-check-label" for="source_descriptions">Descriptions</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="source_comments" name="Comments">
<label class="form-check-label" for="source_comments">Comments</label>
</div>
<span>{{ form_sources_required }}
</div>
<div class="form-row mt-3">
<div class="col-md-12">
<p>Second, filter documents based on the metadata, if desired:</p>
</div>
</div>
{% for category in categories %}
{% if forloop.counter0|divisibleby:3 %}
<div class="form-row">
{% endif %}
<div class="col">
<label>{{ category.label }}</label>
<select class="selectpicker" name="{{ category.label }}" multiple data-size="10">
{% for option in category.options %}
<option>{{ option }}</option>
{% endfor %}
</select>
</div>
{% if forloop.counter|divisibleby:3 %}
</div>
{% endif%}
{% endfor %}
<div class="form-row mt-3">
<div class="col-md-12">
<div class="form-group">
<label for="wordcloud_name">Finally, give your wordcloud a name</label>
<input type="text" name="wordcloud_name" class="form-control" id="wordcloud_name" placeholder="Enter your wordcloud name">
<div class="invalid-feedback">{{ form_cloud_name_required }} {{ form_duplicate_cloud_name_error }}</div>
</div>
</div>
</div>
<div class="form-row mt-3">
<div class="col-md-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
A picture of the rendered form:
You can create a django form with the same field names as your html form.
After you submit the form you can check if it valid:
form = YourForm(request.POST)
# check whether it's valid:
if form.is_valid():
...
Then if the form is not valid you can show the errors in your template like so:
<div class="form-group">
<label for="wordcloud_name">Finally, give your wordcloud a name</label>
<input type="text" name="wordcloud_name" class="form-control" id="wordcloud_name" placeholder="Enter your wordcloud name">
<div class="invalid-feedback">{{ form.wordcloud_name.errors }}</div>
</div>

Manually rendered form fields do not save data

I really wanted to figure this out myself and I spent over 4 hours on the subject but I give up now.
I have a form that is supposed to save data, and if I lay out the form with the {{ form }} tag everything works great. If I put in to form with individual tags like {{ form.client_email }}, the form data is not saved to the database.
I need to render these fields manually for front end purposes but I just couldn't figure out how to do it.
I appreciate your help a lot.
Here is my code.
views.py
def client_list_view(request):
if request.method == 'POST':
form = ClientModelForm(request.POST)
if form.is_valid():
client_title = form.cleaned_data["client_title"]
client_email = form.cleaned_data["client_email"]
client_turkishid_no = form.cleaned_data["client_turkishid_no"]
client_tax_no = form.cleaned_data["client_tax_no"]
client_tax_office = form.cleaned_data["client_tax_office"]
client_contactperson = form.cleaned_data["client_contactperson"]
client_phone_number = form.cleaned_data["client_phone_number"]
Client.objects.create(
client_title=client_title,
client_email=client_email,
client_turkishid_no=client_turkishid_no,
client_tax_no=client_tax_no,
client_tax_office=client_tax_office,
client_contactperson=client_contactperson,
client_phone_number=client_phone_number
).save()
return redirect("books:client-list")
else:
form = ClientModelForm()
client_list = Client.objects.all().order_by("client_title")
context = {'client_list' : client_list, "form": ClientModelForm}
return render(request, 'clients/client_list.html', context=context)
Working template
<div id="clientModal" class="modal bottom-sheet">
<div class="modal-content">
<form method="POST">
{% csrf_token %}
{{form}}
<button class="btn">Ekle</button>
</form>
</div>
</div>
Not Working Template
<div id="clientModal" class="modal bottom-sheet">
<div class="modal-content">
<div class="row">
<div class="col s12">
<ul class="tabs">
<li class="tab col m6"><a class="active" href="#gercek">Gerçek Kişi</a></li>
<li class="tab col m6"><a class="active" href="#tuzel">Tüzel Kişi</a></li>
</ul>
</div>
<div id="gercek" class="col s12">
<div class="col s12 m12 l12">
<div id="inline-form" class="scrollspy">
<div class="card-content">
<form method="POST">
{% csrf_token %}
<div class="row">
<div class="input-field col m4 s12">
<i class="material-icons prefix">email_outline</i>
{{form.client_email}}
<label for="{{ form.client_email.id_for_label }}">Müvekkilin E-Posta Adresi</label>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="tuzel" class="col s12">
<div class="col s12 m12 l12">
<div id="inline-form" class="scrollspy">
<div class="card-content">
<form method="POST">
{% csrf_token %}
<div class="row">
<div class="input-field col m4 s12">
<i class="material-icons prefix">account_circle</i>
{{form.client_title}}
<label for="{{ form.client_title.id_for_label }}">Müvekkilin Unvanı</label>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
In your "not working" template you wrap each of individually rendered field with a form tag. That's not the correct way to do what you need. Just keep one form tag like you do in the working template and render all fields inside:
<div id="clientModal" class="modal bottom-sheet">
<div class="modal-content">
<form method="POST">
{% csrf_token %}
<!-- put your fields here with any additional markup you need -->
{{ form.client_email }}
<label for="{{ form.client_email.id_for_label }}">Müvekkilin E-Posta Adresi</label>
{{ form.client_title }}
<label for="{{ form.client_title.id_for_label }}">Müvekkilin Unvanı</label>
<!-- by the way you can use form.<field>.label_tag -->
{{ form.client_phone_number }}
{{ form.client_phone_number.label_tag }}
<!-- and maybe you'd also like to render errors -->
{{ form.client_phone_number.errors }}
<button class="btn">Ekle</button>
</form>
</div>
</div>
Also, the ClientModelForm seems to be an instance of ModelForm, so you do not need to deal with form.cleaned_data manually. For new objects you can just call form.save(commit=True):
if form.is_valid():
form.save(commit=True)

Is it correct use for Django ModelForm

My question; i'm used ModelForm instead of forms.Form and i want to organize form in html file instead of forms.py file (i don't want to use attr tag because my form.html file is very complicated) Is this usage correct?
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model=Comment
fields=[
'name',
'email',
'comment',
]
html file
<form class="post-comment-form" method="POST">
{% csrf_token %}
{% if form.errors %}
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
{% endif %}
<div class="form-row">
<div class="form-item half blue">
<label for="id_name" class="rl-label" >Name</label>
{{ form.name}}
</div>
<div class="form-item half blue">
<label for="id_email" class="rl-label" >Email</label>
{{ form.email}}
</div>
</div>
<div class="form-row">
<div class="form-item blue">
<label for="id_comment" class="rl-label">Comment</label>
{{ form.comment }}
</div>
</div>
<button type="submit" class="save-button">Submit</button>
If you don't want to use the {{form}} then you have to give the input field for each model's fields like <input type="text" name = "name"> .For example
<div class="form-row">
<div class="form-item half blue">
<label for="id_name" class="rl-label" >Name</label>
**<input type="text" name = "name">**
</div>
<div class="form-item half blue">
<label for="id_email" class="rl-label" >Email</label>
<input type="text" name = "email">
</div>
</div>
<div class="form-row">
<div class="form-item blue">
<label for="id_comment" class="rl-label">Comment</label>
<input type="text" name = "comment">
</div>
</div>
<button type="submit" class="save-button">Submit</button>
On the html you can have something like this
{% csrf_token %}
{{ form.as_p }}
and then proceed with styling or better yet you can use {% crispy %} which personal I find it great based on what you want to archive, your forms.py looks ok.

bootstrap and django keep button and input on same line

I would like to be my select input and button on the same line.
This i can get to work, but my input is stretched to the col width and not the input width.
How can i achieve this?
my code so far:
<form action="{% url 'register_user' %}" method="post">
{% csrf_token %}
<div class="row">
{% for field in filter_form %}
<div class="col-md-9">
<div class="form-group">
{{ field|addcss:"form-control" }}
</div>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary btn-sm">Filter</button>
</div>
{% endfor %}
</div>
</form>
What am i missing?
Side note: is there some way to make my button a bit wider than the text in it?
First you need to understand what the following code does. It creates a column of width 9/12 the width of the page.
<div class="col-md-9">
You might wan to do the following.
<div class="col-md-9">
<div class="form-group">
{{ field|addcss:"form-control" }}
<button type="submit" class="btn btn-primary btn-sm">Filter</button>
</div>
</div>
Give explicit width to the button. Check online to give width inline

Additional fields to model with separate forms

I have a model Customer which has some general fields like name phone etc and some fields that are more private like ssn id tax_id etc. so it is like this
class Customer(models.Model):
#general fields
#more private staff fields
I want to have one form to create a new customer but I want them to be in different tabs (well my employer does want that). What would be the best practice? Have different models so different forms?
class Customer(models.Models):
#general fields
class PrivateFields(models.Model):
#private fields
customer = models.OneToOneField(Customer)
The above method would require the usage of two different forms to be rendered in one template. If I want one form (first method one model) would something like that stand or will it have issues:
I am using bootstrap3:
<ul class="nav nav-tabs" id="myTab">
<li>General</li>
<li>Private</li>
</ul>
<form class="inline">
<div class="tab-content">
<div class="tab-pane active" id="general-info">
<div class="row">
<div class="form-group col-md-6">
<label for="text">Home</label>
<input type="text" id="text" class="form-control input-sm" placeholder="Small">
</div>
</div>
</div>
<div class="tab-pane" id="private-details">
<div class="row">
<div class="form-group col-md-6">
<label for="profile">Profile</label>
<input type="text" id="profile" class="form-control input-sm" placeholder="profile">
</div>
</div>
</div>
</div>
<div class="row">
<input type="submit" class="btn btn-primary" value="Submit form">
</div>
</form>
bootply link
I can't see any reason to have them in separate models, or even two separate forms. Tabs are just divs that are shown/hidden by some Javascript, so you can simply put the 'public' fields in one div and the 'private' ones in the other.
<div class="tab-pane" id="general-info">
<div class="field">
{{ form.generalfield1.label_tag }}
{{ form.generalfield1 }}
{{ form.generalfield1.errors }}
</div>
... etc ...
</div>
<div class="tab-pane" id="general-info">
<div class="field">
{{ form.privatefield1.label_tag }}
{{ form.privatefield1 }}
{{ form.privatefield1.errors }}
</div>
... etc ...
</div>
If you want to do it in a more generic way, perhaps you could define a list of public/private field names in the view:
public_fields = ['name', 'address']
private_fields = ['trustworthy', 'bank_details']
and check membership as you iterate through:
<div class="tab-pane" id="general-info">
{% for field in form %}
{% if field.name in public_fields %}
<div class="field">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
{% endif %}
{% endfor %}
</div>
etc.