Manually rendered form fields do not save data - django

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)

Related

Problems with a backend part of search line in Django

who can explain me why my SearchView doesn't work. I have some code like this.It doesn't show me any mistakes, but it doesn't work. The page is clear. Seems like it doesn't see the input.
search.html
<div class="justify-content-center mb-3">
<div class="row">
<div class="col-md-8 offset-2">
<form action="{% url 'search' %}" method="get">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search..." />
<div class="input-group-append">
<button class="btn btn-dark" type="submit" id="button-addon2">Search</button>
</div>
</div>
</form>
</div>
</div>
</div>
search/urls.py
path('search/', SearchView.as_view(), name='search')
search/views.py
class SearchView(ListView):
model = Question
template_name = 'forum/question_list.html'
def get_queryset(self):
query = self.request.GET.get("q")
object_list = Question.objects.filter(
Q(title__icontains=query) | Q(detail__icontains=query)
)
return object_list
forum/question_list.html
{% extends 'main/base.html' %}
{% block content %}
{% for question in object_list %}
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title">{{ question.title }}</h4>
<p class="card-text">{{ question.detail }}</p>
<p>
{{ question.user.username }}
5 answers
10 comments
</p>
</div>
</div>
{% endfor %}
{% endblock %}

Django - How to apply onlivechange on CharField / IntegerField

I want to hide the field form.name_of_parent_if_minor if the age (CharField) < 18 else show. I am not getting where to write jQuery or JS code or add separate js file. For this do I need to the html definition and add tag for age (CharField) or we can perform action on this as well.
I am new to the Django so if you find any mistakes in my code then any help would be appreciated for guidance.
forms.py
class StudentDetailsForm(forms.ModelForm):
class Meta:
model = StudentDetails
views.py
class StudentCreateView(LoginRequiredMixin, CreateView):
template_name = 'student/student_details_form.html'
model = StudentDetails
form_class = StudentDetailsForm
success_url = "/"
html
{% extends 'student/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div id="idParentAccordian" class="content-section">
<form method="POST">
{% csrf_token %}
<div class="card mt-3">
<div class="card-header">
<a class="collapsed card-link" style="display: block;" data-toggle="collapse"
href="#idPersonalInformation">Personal Information</a>
</div>
<div id="idPersonalInformation" class="collapse show" data-parent="#idParentAccordian">
<div class="card-body">
<div class="row">
<div class="col-6">
{{ form.joining_date|as_crispy_field }}
</div>
<div class="col-6">
{{ form.class|as_crispy_field }}
</div>
</div>
{{ form.student_name|as_crispy_field }}
{{ form.father_name|as_crispy_field }}
{{ form.mother_name|as_crispy_field }}
{{ form.gender|as_crispy_field }}
<div class="row">
<div class="col-6">
{{ form.date_of_birth|as_crispy_field }}
</div>
<div class="col-6">
{{ form.age|as_crispy_field }}
</div>
</div>
<div>
{{ form.name_of_parent_if_minor|as_crispy_field }}
</div>
</div>
</div>
</div>
<div class="form-group mt-3">
<button class="btn btn-outline-info" type="submit">Save</button>
<a class="btn btn-outline-secondary" href="javascript:history.go(-1)">Cancel</a>
</div>
</form>
</div>
{% endblock content %}
the easiest way but not the cleanest is to add JS script in your html
the recommanded way is to add static folder to your app and load static files in your html template using {% load static %}

How can I get the validation errors from flask_wtforms

I would like to get validation errors from a textarea form from flask_wtforms. I know that you can get them by including this in the html :
{% for error in form.post.errors %}
{{ error }}
{% endfor %}
But that doesn't quite work for me because Im using a bootstrap modal and the Length validation requires you to submit the form, refreshing the page, unlike the DataRequired() validator which prevents you from submitting. And its hard to tell that the form failed.
Basically I would like to get the errors from the python end and flash them.
I've tried to access the errors with form.post.errors but it doesn't work, it always returns an empty set.
This is the code for my index
def index():
form = PostForm()
// I would like to get the errors via form.post.errors here and I don't understand why I can't
if form.validate_on_submit():
post = Post(body=form.post.data, author=current_user)
db.session.add(post)
db.session.commit()
flash('Your post is now live!', 'primary')
return redirect(url_for('index'))
page = request.args.get('page', 1, type=int)
posts = current_user.followed_posts().paginate(page, app.config['POSTS_PER_PAGE'], False)
next_url = url_for('index', page=posts.next_num) if posts.has_next else None
prev_url = url_for('index', page=posts.prev_num) if posts.has_prev else None
return render_template('index.html', title='Home', posts=posts.items, form=form, next_url=next_url, prev_url=prev_url)
{% extends "base.html" %}
{% block content %}
{% if form %}
<div class="modal fade" id="submitPost" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form action="" method="post">
{{ form.hidden_tag() }}
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="submitPostLabel">Submit Post</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="PostText">{{ form.post.label }}</label>
{{ form.post(cols=32, rows=4, class="form-control") }}<br>
</div>
</div>
<div class="modal-footer">
<!-- <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> -->
{{ form.submit(class="btn btn-primary") }}
</div>
</div>
</form>
</div>
</div>
{% endif %}
the above html file is basically
<form action="" method="post">
{{ form.hidden_tag() }}
{{ form.post.label }}
{{ form.post(cols=32, rows=4, class="form-control") }}
{{ form.submit(class="btn btn-primary") }}
</form>
with some bootstrap
You can print the errors by adding the following: print form.errors.items().
form.errors

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.

Doesn't populate fields with existing data

When I access the update page it doesn't populate the fields with the existing entry data (which is there, and print statements I've placed in parts of the view show that it's accessible and exists), I'm not really sure why it's not populating.
This is my view:
#login_required
def sites_update_view(request, place_id=None):
if place_id:
place = get_object_or_404(SiteMeta, pk=place_id)
else:
return redirect('sites-index')
if request.POST:
form = SitesAddForm(request.POST, instance=place)
if form.is_valid():
form.save()
return redirect('sites-index')
else:
form = SitesAddForm(instance=place)
return render(request, 'sites-update.html', {
'form': form,
'site': place,
'place_id': place_id
})
My template:
{% extends "newbase.html" %}
{% load url from future %}
{% load floppyforms %}
{% load staticfiles %}
{% block title %} - Update Site {% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-6 col-md-6">
<h3 class="heading">Update Surveillance Site</h3>
<form method="post" action={% url 'sites-update' place_id=site.pk %}>
{% csrf_token %}
<div class="formSep">
<div class="row">
<div class="col-sm6 col-md-6">
<label for="id_name">Site Name:<span class="f_req">*</span></label>
{{ form.name }}
<span class="help-block">What is the site name?</span>
</div>
<div class="col-sm-6 col-md-6">
<label for="id_lga">LGA:<span class="f_req">*</span></label>
{{ form.lga }}
<span class="help-block">What is the LGA?</span>
</div>
<div class="col-sm-6 col-md-6">
<label for="id_site_type">Site Type:<span class="f_req">*</span></label>
{{ form.site_type }}
<span class="help-block">What type of site is this?</span>
</div>
<div class="col-sm-6 col-md-6">
<label for="id_site_priority">Site Priority:<span class="f_req">*</span></label>
{{ form.site_priority }}
<span class="help-block">What is the priority of this site?</span>
</div>
<div class="col-sm-6 col-md-6">
<label for="id_site_category">Site Category:<span class="f_req">*</span></label>
{{ form.site_category }}
<span class="help-block">What category should the site be in?</span>
</div>
</div>
</div>
<div class="row">
<input class="btn btn-default" type="submit" value="Save" />
<a class="btn btn-default" href={% url "sites-index" %}>Cancel</a>
</div>
</form>
</div>
</div>
{{ form.errors }}
{% endblock %}
{% block sidebar %}
{% include "afp-sidebar.html" %}
{% endblock %}
if request.POST: should be if request.method == 'POST':