Rendering django model validation error in template - python

I am building a web application on django. As part of this, I have created one html form like following:
<form method="post" action="/voting/add_state/">{% csrf_token %}
State name:<br>
<input type="text" name="state_name"><br>
<input type="submit" value="Submit">
</form>
In models.py I have added unique constraint validation on name like following:
class State(models.Model):
name = models.CharField(max_length=200, unique=True)
vote_counted = models.BooleanField(default=False)
So for duplicate name, it throws a unique constraint error which I would like to capture in the template. Can anyone please give any suggestion.

Create a form based on your model
#forms.py
from django import forms
from .models import State
class StateForm(forms.ModelForm):
class Meta:
model = State
fields = ('name',)
now use this form on your views
#views.py
from django.views.generic import FormView
from .forms import StateForm
class MyView(FormView):
template_name = 'template.html'
form_class = StateForm
success_url = '/my-url-to-redirect-after-submit/'
template.html
<form method="post">
{% csrf_token %}
Name
{{ form.name }}
{{ form.name.errors }}
<input type="submit" value="Create">
</form>

Django has Form processing built in. Django has "Model Forms", which automatically render the form for your model. If you pass it through the view and reference it in the context it will automatically generate the html for you, but if you would like more control over what is rendered in the template then you can reference the form attributes that Django Model Form produces.
I strongly suggest working within the framework Django provides to you for building forms; it provides a lot of boilerplate code for building, validating and abstracting forms and is especially competent for simple forms like these.
Here is an example:
models.py
class State(models.Model):
name = models.CharField(max_length=200, unique=True)
vote_counted = models.BooleanField(default=False)
forms.py
class StateForm(forms.ModelForm):
model = State
fields = (name,)
views.py
from django.views.generic.edit import FormView
class StateForm(FormView):
template_name = 'state_form.html'
form_class = StateForm
success_url = '/thanks/'
state_form.html (example of auto generated form)
{{ form }}
state_form.html (example of custom form)
<form action="/" method="post">
{% csrf_token %}
{{ form.errors }}
{% for field in form %}
<input type="{{ field.type }}" name='{{ field.name }}' class="submit" value="{{ field.value}}">
{% endfor %}
<input type="submit" name='submit" value="Submit">
</form>
References:
Django Forms:
https://docs.djangoproject.com/en/1.9/topics/forms/
Django Model Forms: https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/
Django Generic Views:
https://docs.djangoproject.com/en/1.9/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView

You could create a form for State model and create the validator, so if the user try with a duplicate name, the form raise a message something like this:
models.py
class State(models.Model):
name = models.CharField(max_length=200, unique=True)
vote_counted = models.BooleanField(default=False)
forms.py
def unique_name(value):
exist = State.objects.filter(name=value)
if exist:
raise ValidationError(u"A state with the name %s already exist" % value)
class StateForm(forms.Form):
name = forms.CharField(label=('Name:'), validators=[unique_name])
Then you just need to render the StateForm in the template.

Related

Python Django Form submit button not working as desired

I have been trying to learn Django.
I am stuck on this form part. A form has been created that allows the user to create an Album object where they can fill in the Artist, Album Name, Genre and upload an Album Logo. When I fill in the fields and then click submit, it should then redirect me to the details page for that particular Album that just got created. But nothing appears to happen when clicking the submit button and the object does not get created.
Here is the models.py code that contains an Album class with 4 fields; artist, album_name, genre and album_logo.
from django.db import models
from django.urls import reverse
# Create your models here.
class Album(models.Model):
artist = models.CharField(max_length=250)
album_name = models.CharField(max_length=500)
genre = models.CharField(max_length=100)
album_logo = models.ImageField()
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk':self.pk})
def __str__(self):
return self.album_name + " - " + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=100)
song_title = models.CharField(max_length=250)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
Here is the album_form.html code which contains the actual form. I have not used crispy_forms as I am not familiar with Bootstrap though I know CSS.
{% extends 'music/base.html' %}
{% block title %}Add a New Album{% endblock %}
{% block body %}
<form class="formContainer" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{% if field.label != 'Album logo' %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="text" id="field{{ forloop.counter }}" name="" value="">
{% else %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="file" id="field{{ forloop.counter }}" name="" value="" accept="image/*">
{% endif %}
<br>
{% endfor %}
<input type="submit" id="submitBtn" name="" value="Add">
</form>
{% endblock %}
This is views.py code where I have made use of class based views and not function based views.
from django.views import generic
from .models import Album, Song
# Create your views here.
class IndexView(generic.ListView):
template_name = 'music/index.html'
queryset = Album.objects.all()
context_object_name = 'all_albums'
class DetailView(generic.DetailView):
model = Album
template_name = 'music/detail.html'
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
and finally this is my urls.py code:
from django.urls import path, include
from . import views
app_name='music'
urlpatterns = [
#/music/
path('', views.IndexView.as_view(), name='index'),
#/music/5/
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
#/music/album/add/
path('album/add/', views.AlbumCreate.as_view(), name='album-add')
]
After clicking the submit button in the form, it should take me to the "detail" url for the primary key of the Album that got created. Am I missing something here?
In your views.py you need to override the get_success_url function in your CreateView and pass the id as an argument while redirecting.
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
def get_success_url(self):
return reverse('music:detail', args=(self.object.id,))
Seems you forgot to put action to your <form> tag
Try this
<form class="formContainer" action='{% url 'music:album-add'%}' method="post" enctype="multipart/form-data">
Edit: Also add success url using get_success_url function in your AlbumCreate view to redirect user to album detail page, like was mentioned in above answer
from django.urls import reverse_lazy
...
class AlbumCreate(generic.CreateView):
...
def get_success_url(self, **kwargs):
return reverse_lazy('music:detail', args = (self.object.id,))

How make attribute of model only for user.is_staff?

Model Post has the boolean field moderation, which is intended for publishing after approval by admin users (which have user.is_staff as True.
There is a page "Post update", where an user (the author of the post) and admin users can updated the post info.
I want that the field moderation (which is a checkbox) is shown only if the user is an admin (user.is_staff == True).
models.py
class Post(models.Model):
...
moderation = models.BooleanField(default=True)
...
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'body', 'logo']
views.py
class PostUpdateView(PermissionRequiredMixin, UpdateView):
model = Post
fields = ['title', 'body', 'logo']
permission_required = 'post.can_mark_returned'
post_form.html
{% extends "base_generic.html" %}
{% block content %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit" />
</form>
{% endblock %}
This similar question has some ideas for you.
I can also suggest overriding FormMixin.get_form_class() and using modelform_factory():
from django.forms import modelform_factory
class PostUpdateView(PermissionRequiredMixin, UpdateView):
model = Post
permission_required = 'post.can_mark_returned'
def get_form_class(self)
fields = ['title', 'body', 'logo']
if self.request.user.is_staff:
fields.append('moderation')
return modelform_factory(
self.model,
fields=fields)

The secondary linkage in my webpage cannot display the options in Django 1.10

I use smart_selects to realize secondary linkage in Django admin page. Succeed! When I choose one university, only the colleges those belong to the university can be chosen.
But, when it comes to the form in webpage, the second level form cannot display any option.This is the wrong webpage:
Here are the codes:
models.py
class StudentModel(models.Model):
GENDER_CHOICES = (('M','男'),('F','女'),)
name = models.CharField(verbose_name='姓名',max_length=20)
gender = models.CharField(blank = True,max_length=4,choices = GENDER_CHOICES,verbose_name='性别')
date_of_birth = models.DateField(verbose_name='出生日期',blank=True,null=True)
age = models.IntegerField(verbose_name='年龄',default=0)
highschool = models.ForeignKey(SeniorHighSchoolModel,verbose_name='高中名称')
university = models.ForeignKey(UniversityModel,verbose_name='大学名称')
college = ChainedForeignKey(CollegeModel,chained_field='university',chained_model_field='university',show_all=False,blank=True,null=True,verbose_name='学院名称')
def __str__(self):
return self.name
forms.py
from django import forms
from .models import StudentModel
class LoggingForm(forms.ModelForm):
class Meta:
model = StudentModel
fields=['name','gender','date_of_birth','age','highschool','university','college']
logging.html
<form action="" method="POST">
{% csrf_token %}
{{form.as_p}}
<input type='submit' />
I found an resolution,just add {{form.media.js}} in logging.html.
<form action="" method="POST">
{% csrf_token %}
**{{form.media.js}}**
{{form.as_p}}
<input type='submit' />
<a>You will recieve an email from us.</a>
</form>
The answer is found in this question:
How to use django smart-selects with modelform?
Thanks for the edition from Donald Duck.

django how to catch a variable of a form in template

I want to use feedback forms in my app. And I have FeedBack model and FeedBackForm form.
models.py:
class Feedback(models.Model):
name = models.CharField(max_length=150, blank=True)
email = models.EmailField(blank=True)
comment = RichTextField()
forms.py:
class FeedBackForm(forms.ModelForm):
class Meta:
model = Feedback
fields = ('name', 'email', 'comment')
I used FeedBackForm in my views,py file
views.py
def home(request):
if request.method == 'POST':
feedback_form = FeedBackForm(data=request.POST)
if feedback_form.is_valid():
feedback_form.save()
else:
feedback_form = FeedBackForm()
return render(request, 'home.html', {'feedback_form': feedback_form})
Now my question is: how can I use my variables in template? Instead of this 3 input tags. (Is there another easier way other than
{{ feedbackform.as_p }}
and
{% csrf_token %}
to call my form variables "name", "email" and "comment" as input). Thanks in anvance
<form action="." method="post">
<input type="text" name="name">
<input type="email" name="email">
<textarea name="comment"></textarea>
</form>
If I get your question right, you want to call form.name, form.email and form.comment in template? See more at https://docs.djangoproject.com/ja/1.9/topics/forms/#rendering-fields-manually

Multiple text inputs in django form via Google App Engine

Goal: to create a question where a user creates a poll question that is "mad-libs" style (i.e. "Would you fool around with _(text)__ if she wasnt dating _(text)_?").
Code: This file creates a django form corresponding to an appengine entity.
from django import newforms as forms
import models
from google.appengine.ext.db import djangoforms
class PollForm(djangoforms.ModelForm):
class Meta:
model = models.Poll
This is an excerpt from the models.py file
from google.appengine.ext import db
from django import newforms as forms
class Poll(db.Model):
question = db.StringProperty()
created_on = db.DateTimeProperty(auto_now_add = 1)
created_by = db.UserProperty()
def __str__(self):
return '%s' %self.question
def get_absolute_url(self):
return '/poll/%s/' % self.key()
here is the html for this section
<form action="." method="post">
{{pollform.as_p}}
{% for form in choiceforms %}
{{form.as_p}}
{% endfor %}
<input type="submit" name="createpoll" value="createpoll" />
</form>
Is there a fairly straightforward way to create a question like this with some pre-coded text and some input text? Can I harcode it in the HTML?
Any direction is greatly appreciated!
I still don't totally understand your question. If you post your full source and an example of the result you are trying to get, then you will get a better response.
Here's an example of constructing a form for someone to answer the question. I hard coded the question, but you could easily retrieve that dynamically.
class Answer(models.Model):
answer1 = models.CharField(max_length=100)
answer2 = models.CharField(max_length=100)
class AnswerForm(forms.ModelForm):
class Meta:
model = Answer
def test(request):
if request.method == 'GET':
form = AnswerForm()
question_template = 'Would you fool around with %s if she wasn\'t dating %s?'
html = question_template % (form['answer1'], form['answer2'])
params = {'form': form,
'html': html}
return render_to_response('test.html',
params,
context_instance=RequestContext(request))
Template:
<form method="post" action="">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{{ html|safe }}
<input type="submit" value="Save"/>
</form>

Categories