Control if a field is unique in a django form - django

First error :I want to check if group_name field value is unique in a modelforms
I tried this code but seems not working as if i put a new value in this field, there is no message but data as not been add to table
Second error: i nether have any message. Maybe, I should not redirect pages ?
my code in views.py:
def group_create(request):
group_form = GroupForm()
if request.method == "POST":
group_form = GroupForm(request.POST)
if group_form.is_valid():
group_name = group_form.cleaned_data.get('group_name')
if Group.objects.filter(group_name=group_name).exists:
messages.error(request, 'this group already exists')
else:
group_form.save()
messages.success(request, 'Group created')
return redirect('group_list')
return render(request, 'imports/group_create.html', {
"group_form": group_form,
})
my model:
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
groupParent_id = models.ForeignKey('self', blank=True, null=True, related_name='Parent', on_delete=models.CASCADE)
group_name = models.CharField(max_length=100, null=False, blank=False, unique=True)
my html:
<div class="container-fluid">
<!-- Code pour message type toaster -->
{% if messages %}
<div class="row">
<div class="col-xs-12">
<ul class="alert" role="alert">
{% for message in messages %}
<p {% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</p>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
<!-- fin messages -->
<div class="row">
<div class="col-lg-2 col-md-2 col-sm-2 sidebar">
{% block sidebar %}{% endblock %}
</div>
<div class="col-lg-10 col-lg-offset-2 col-md-10 col-md-offset-2 col-sm-10 col-sm-offset-2 content">
{% block heading %}{% endblock %}
{% block page %}{% endblock %}
</div>
</div>
</div>

Django's ModelForm [Django-doc] already validates the uniqness of fields that you marked unique=True [Django-doc], as is specified in the documentation on Interaction with model validation [Django-doc]:
(...)
The model's clean() method will be called before any uniqueness
checks are made. (...).
If the field is not valid, than it will add that error to the group_form.errors [Django-doc]. The reason why you did not see those is that you, regardless whether the form is valid or not, just redirect to a view, and thus the form is discarded.
If you render the form accordingly, it will add extra messages to the fields with errors:
def group_create(request):
if request.method == "POST":
group_form = GroupForm(request.POST)
if group_form.is_valid():
group_form.save()
messages.success(request, 'Group created')
# only in case of success
return redirect('group_list')
else:
group_form = GroupForm()
return render(request, 'imports/group_create.html', {
"group_form": group_form,
})

Related

rendering form in html django

I have this app and its working but i'm confused whether to use form method or POST.get method. with form i'm getting so many challenges like rendering form on custom html
suppose i have this change password screen, for that i need to create form then use this on html template and with custom html it gets more complicated to use form fields.
forms.py:
class ChangePasswordForm(PasswordChangeForm):
old_password = forms.CharField(label="Old Password", strip=False, widget=forms.PasswordInput(
attrs={'class': 'formField password-genrInput'}))
new_password1 = forms.CharField(label="New Password", strip=False, widget=forms.PasswordInput(
attrs={'class': 'formField password-genrInput'}))
new_password2 = forms.CharField(label="Confirm Password", strip=False, widget=forms.PasswordInput(
attrs={'class': 'formField password-genrInput'}))
class Meta:
model = User
fields = ('old_password', 'new_password1', 'new_password2')
views.py:
# Password Change View
def changePassword(request):
if request.method == 'POST':
form = ChangePasswordForm(request.user, request.POST)
print(form)
if form.is_valid():
print("form valid")
user = form.save()
update_session_auth_hash(request, user)
messages.success(request, "Password Changed Successfully")
return redirect('changePassword')
else:
messages.error(request, "Something Went Wrong, Please Try Again ")
return redirect('changePassword')
else:
form = ChangePasswordForm(request.user)
return render(request, 'admin/user_auth/change_password.html', {
'form': form
})
html:
{% extends "admin/layouts/default.html" %}
{% load static %}
{% block content%}
<div class="row">
<div class="col">
<div class="titleBlock">
<h1><i class="fas fa-chevron-circle-left mr-3"></i>Back</h1>
</div>
<div class="card">
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li {% if message.tags %} class=" {{ message.tags }} " {% endif %}> {{ message }} </li>
{% endfor %}
</ul>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="formBlock">
<div class="row password-genr mt-5">
{% for field in form %}
<div class="col-md-7">
<div class="formControl static ">
<label for="" class="formLabel">{{field.label}}</label>
{{field}}
</div>
</div>
{%endfor%}
<div class="col-md-7">
<div class="btnBlock mt-5">
<button type="submit" class="btn btn-md">Save</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
{%endblock content%}
but with simple method i would have checked first if new password and confirm password are matching then
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
check the old password are matching with db then save the new password on db.
so which method should i use and why?
TO do This you can do something like this.
from django.contrib.auth.hashers import check_password
current_password = request.user.password
old_password = request.POST.get('old_password')
matchcheck= check_password(old_password, current_password) #this returns True or False
if matchcheck:
#change your password
else:
#tell the user the password is wrong.
The method above is useful by example if a user wants to delete his account to do so you can use the idea to check whether he knows his password or not ,if he knows it then he can delete his account.
And if you do not want to implement it by yourself you can use the built-in in Django(i really recommend this method for changing password because it well done and less headache).

How to create a django formset or form add/edit page in order to edit several records

For one of my open source projects, I need to create ONE add/edit page in order to make possible to edit several records with one save.
The repo is an IMDB clone formed for learning purpose. A user can add her/his favorite genres in her/his profile. Then an edit page is formed to show the list of those favored genres and the movies within that genre. (A for loop here) User can add notes, watch list options and so on to those movies. (NOT a FORMSET)
However, the code doesn't work as expected. The page cannot be saved and only the first checkbox of the list can be changed.
There is no error.
NOTE:
You can install repo with dummy data.
(https://github.com/pydatageek/imdb-clone)
Then after logging in, select your favorite genres. (http://localhost:8000/users/profile/)
Then (I wish it can be solved here) you can see the movies with your selected genres. Add notes, to watch list... (http://localhost:8080/users/profile/movies2/)
# users/templates/user-movies-with_loop.html
{% extends 'base.html' %}{% load crispy_forms_tags %}
<!-- Title -->
{% block htitle %}Your movies from favorite genres{% endblock %}
{% block title %}Your movies from favorite genres{% endblock %}
{% block content %}
<div class="card card-signin">
{% include 'users/profile-menu.html' %}
<h3 class="card-title text-center my-4">Take notes for your movies <small></small></h3>
<hr class="mb-1">
<div class="card-body">
<form method="POST">
{% csrf_token %}
{% for genre in user.genres.all %}
<h2 for="genre" name="genre" value="{{ genre.id }}">{{ genre.name }}</h2>
{% for movie in genre.movies.all %}
<div class="ml-5">
<h4>{{ movie.title }}</h4>
{{ form|crispy }}
</div>
<input type="hidden" name="user" value="{{ user.id }}">
<input type="hidden" name="movie" value="{{ movie.id }}">
{% empty %}
<p class="alert alert-danger">The genre you have selected on your profile doesn't have any movies!</p>
{% endfor %}
{% empty %}
<p class="alert alert-danger">You should select genres with movies from your profile to edit here!</p>
{% endfor %}
<input class="btn btn-lg btn-primary btn-block text-uppercase" type="submit" value="Submit">
</form>
</div>
</div>
{% endblock %}
# users.forms.py
...
class UserMovieFormWithLoop(ModelForm):
genre = forms.HiddenInput(attrs={'disabled': True})
class Meta:
model = UserMovie
fields = ('user', 'movie', 'note', 'watched', 'watch_list')
widgets = {
'user': forms.HiddenInput,
'movie': forms.HiddenInput,
'watched': forms.CheckboxInput(),
}
...
# users.models.py
...
class UserMovie(models.Model):
"""
Users have notes about their favorite movies.
"""
user = models.ForeignKey(User, on_delete=models.CASCADE)
movie = models.ForeignKey('movies.Movie', default=1, on_delete=models.CASCADE)
note = models.CharField(max_length=250, null=True, blank=True)
watched = models.BooleanField(default=False, verbose_name='Have you seen before?')
watch_list = models.BooleanField(default=False, verbose_name='Add to Watch List?')
def __str__(self):
return f'{self.user.username} ({self.movie.title})'
...
# users.views.py
...
class UserMovieViewWithLoop(LoginRequiredMixin, CreateView):
model = UserMovie
template_name = 'users/user-movies-with_loop.html'
form_class = UserMovieFormWithLoop
success_message = 'your form has been submitted.'
success_url = reverse_lazy('users:user_movies2')
def form_valid(self, form):
user = self.request.user
movie_counter = Movie.objects.filter(genres__in=user.genres.all()).count()
f = form.save(commit=False)
f.user = user
for i in range(movie_counter):
f.pk = None
f.save()
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super(UserMovieViewWithLoop, self).get_context_data(**kwargs)
context['form'] = self.form_class
return context
def get_object(self):
user = self.request.user
return UserMovie.objects.get(user=user)
...

Why Django return form is invalid?

I have a problem whit a function, when I use the tag {{form.image_cliente}} always return a "form is invalid" and don't save nothing but if I use the tag {{form.as_p}} return a form is valid and save the field image_cliente, and I dont know why, I just want to display only the form.image_cliente in the template.
Mys form Cliente:
class ClienteForm(forms.ModelForm):
id_tipo_cliente = forms.ModelChoiceField(queryset=Tipo_cliente.objects.filter(status=1), label="Tipo de cliente" ,empty_label="Seleciona tipo", widget=forms.Select(attrs={'value':'form-control'}))
password = forms.CharField(label="Password", required=False,
widget=forms.PasswordInput)
class Meta:
model = Cliente
exclude = ['status', 'id_usuario_alt', 'fecha_creacion', 'fecha_modificacion', 'fecha_cancelacion']
fields = [
'nombres',
'apellidos',
'usuario',
'password',
'correo_electronico',
'direccion',
'telefono',
'telefono_celular',
'id_tipo_cliente',
'image_cliente',
]
labels = {'nombres':'Nombres', 'apellidos':'Apellidos', 'usuario':'Usuario', 'correo_electronico':'Correo', 'direccion':'Direccion', 'telefono':'Telefono', 'telefono_celular':'Celular', }
widgets = {
'nombres': forms.TextInput(attrs={'class':'form-control'}),
'apellidos': forms.TextInput(attrs={'class':'form-control'}),
'usuario': forms.TextInput(attrs={'class':'form-control'}),
'correo_electronico': forms.TextInput(attrs={'class':'form-control'}),
'direccion': forms.TextInput(attrs={'class':'form-control'}),
'telefono': forms.TextInput(attrs={'class':'form-control'}),
'telefono_celular': forms.TextInput(attrs={'class':'form-control'}),
'image_cliente':forms.ClearableFileInput(attrs={'multiple': True, 'class':'file', 'data-show-upload':'false', 'data-show-preview':'false'})
}
This is my def function in my views:
def subirIMGCliente(request, pk):
clientes = get_object_or_404(Cliente, pk=pk)
if request.method == 'POST':
form = ClienteForm(request.POST, request.FILES, instance=clientes)
if form.is_valid():
clientes = form.save(commit=False)
if clientes.password == '':
clientes.save(update_fields=['image_cliente'])
print('yes');
return redirect('BackEnd:cliente')
else:
print('form in not valid');
else:
form = ClienteForm(instance=clientes)
return render(request, 'back/Modulo_cliente/imagenes_cliente.html', {'form': form })
My Template
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="form-group">
{{form.image_cliente}}
</div>
</div>
</div>
</br>
<br> <div class="row">
<div class="col-md-8 col-md-offset-2">
<button class="btn btn-success" type="submit">Guardar</button>
<span>Regresar</span>
</div>
</div>
</div>
</form>
the following fields are required:
usuario
nombres
direccion
apellidos
id_tipo_cliente
correo_electronico
telefono
telefono_celular
Add a required=False on them like you have on the password field, and you'll be on your way.
You add an instance for the object, and that object has values for all the required form fields, so when you load form.as_p, or any other tag that outputs the entire form, it loads with all the required fields filled out. That way, when the form is submitted, there are no validation errors. Validity checks are done over request.POST and not on the original model instance, so when the form is submitted without some of the required fields, you get validation errors.
To debug these sorts of issues, add a {{form.errors}} somewhere in your template. That's how I found the errors in your form.
It's considered best practice to display all non-field related errors in a list at the top of the form and field-related errors next to each form field.
So you'd add something like this at the top of the template:
<ol>
{% for error in form.non_field_errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
And something like this for the image_cliente form field:
{% if form.image_cliente.errors %}
<ol>
{% for error in form.image_cliente.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}

Showing custom error messages in django model form with bootstrap

I want to show custom error messages, if some field is not valid. I have following model:
class Test(models.Model):
name = models.IntegerField(max_length=10)
class TestForm(forms.ModelForm):
class Meta:
model = Test
fields = '__all__'
error_messages = {
'name': {
'max_length': ("This user's name is too long."),
},
}
The view is:
def test(request):
if request.method == 'POST':
print "The form is submitted successfully."
form = TestForm(request.POST)
if form.is_valid():
print request.POST.get("name")
return render(request, 'test.html',{'form' : TestForm()})
else:
print "Something wrong with inputs."
return render(request, 'test.html',{'form' : form})
else:
return render(request,'test.html',{'form' : TestForm()})
and template is:
{% extends "base.html" %}
{% block title %}
Test Form
{% endblock title %}
{% load widget_tweaks %}
{% block body_block %}
<h1>hello from test</h1>
<form class='form-horizontal' role='form' action="." method="POST">
<div class='form-group'>
<label class='control-label col-md-2 col-md-offset-2' for='id_name'>Name</label>
<div class='col-md-6'>
{% render_field form.name class="form-control" placeholder="Full Name" type="text" %}
{{ form.name.error_messages }}
{# I want to add here classes for alert-error etc #}
</div>
</div>
{% csrf_token %}
<div class='form-group'>
<div class='col-md-offset-4 col-md-6'>
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
{% endblock body_block %}
But, I am not getting any messages in the template. Please help me to solve this.
Change form.name.error_messages to form.name.errors in your template.
It seems you render fields/errors one by one manually, explained here:
You may want to consider a more automatic approach using a {% for %} template tag.
EDIT: To change the default error message, you need to update your error_messages in the form Meta and overwrite the key used by django, in this case it is key invalid, based on IntegerField source:
class Meta:
model = Test
fields = '__all__'
error_messages = {
'some_integer_field': {
'invalid': 'some custom invalid message',
},
}

Django modelform is submitted, but data is not saved?

Okay Guys, I have a custom User Registration form, whenever the form is submitted a browser alert pops up saying "The Page at 127.0.0.1:8000 says: Submitted!" and nothing happens. No data is saved. Following is the code of the Index view where i am trying to save the form:
def Index(request):
"""View to serve the index page."""
regform = models.RegistrationForm()
loginform = models.LoginForm()
if request.method == 'POST':
if 'signup' in request.POST:
form = models.RegistrationForm(request.POST)
if form.is_valid():
form.save()
message = 'Your Account has been created. You may login now.'
return shortcuts.render_to_response(
'index.html', {'message' : message, 'regform' : regform, 'loginform' : loginform})
else:
message = 'Error: Please fill in all the fields and try again'
return shortcuts.render_to_response(
'index.html', {'regform' : regform, 'message' : message, 'loginform' : loginform})
elif 'login' in request.POST:
requser = request.POST['loginemail']
reqpass = request.POST['loginpass']
'''check if email exists'''
emailexist = models.member.objects.filter(Email=requser).count()
if emailexist == 1:
exists = True
else:
exists = False
'''if email exists check for password'''
if exists == True:
mem = models.member.objects.get(Email=requser)
if reqpass == mem.Password:
request.session['member_id'] = mem.id
return shortcuts.render_to_response(
'login.html')
else:
error = 'You entered an invalid Password, Please try again.'
return shortcuts.render_to_response(
'index.html', {'error' : error, 'regform' : regform, 'loginform' : loginform})
else:
error = 'That E-mail Address is Not Registered, Please Check the spelling and try again.'
return shortcuts.render_to_response(
'index.html', {'regform' : regform, 'loginform' : loginform, 'error' : error})
else:
return shortcuts.render_to_response(
'index.html', {'regform' : regform, 'loginform' : loginform})
Sorry, Here's the Code to the model and registration form
Model:
class member(models.Model):
"""Model to represent a User."""
First_Name = models.CharField(max_length=100, blank=False)
Last_Name = models.CharField(max_length=100, blank=False)
Stage_Name = models.CharField(max_length=100, unique=True, blank=False)
Account_Type = models.CharField(max_length=200, choices=USERTYPE_CHOICES, blank=False)
Password = models.CharField(max_length=100, blank=False)
Email = models.EmailField(max_length=100, blank=False)
Sex = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=False)
Birthday = models.CharField(max_length=2, blank=False)
def __unicode__(self):
return self.Email
Registration Form:
class RegistrationForm(forms.ModelForm):
Stage_Name = forms.CharField(label='Username')
Email = forms.CharField(initial='you#example.com')
Birthday = forms.CharField(initial='dd/mm/yyyy')
Password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model=member
And here is the template :::::
{% extends 'base.html' %}
{% load login_checkbox %}
{% block topbar %}
<head>
</head>
<body>
<div id="logo" class="left"><img src="/static/images/logo.png" alt="Muzikube" width="200" height="52" border="0"/></div>
<div id="login" class="right">
<form id="loginform" action="." method="post">
{% for field in loginform %}
{% if field.field.widget|is_checkbox %}
<div class="checkbox">{{field}}{{field.label_tag}}<span id="forgotpass">Can't Sign In?</span></div>
{% else %}
{{field.label_tag}}{{field}}
{% endif %}
{% endfor %}
<input id="submit" class="submit" "type="submit" name="login" value="In!" />
</form>
{% if error %}
{{error}}
{% endif %}
</div>
<div class="clear"></div>
</body>
{% endblock topbar %}
{% block content %}
<body>
<div class="left">
<div id="heading">Connect To Other Musicians</div>
<div class="subheading">Upload your music, Share Pictures, Share Videos, Make Friends, Get Known !</div>
<div id="homepageimage"><img src="/static/images/comm.png" alt="Connect to other Musicians Around the world!" width="450" height=""/></div>
<div class="subheading">Muzikube let's you connect to other people around the world that share same interests as you !</div>
</div>
<div id="registrationform" class="right">
<div id="form-title">Sign Up, It's Free !</div>
<div id="form-subtitle">Connect to other musicians around the world.</div>
<div class="border"></div>
<div class="error">
{% if message %}
{{message}}
{% endif %}
</div>
<form id="regform" action="." method="post">
<table>
{{ regform.as_table }}
</table>
<input id="register-submit" class="submit" type="submit" name="signup" value="Sign Up" />
</form>
<div class="border"></div>
</div>
<div class="clear"></div>
</body>
{% endblock content %}
It's a little hard to tell from the code above, but I would guess that you get a POST that doesn't have 'login' or 'signup' in (I can't see why it would have those parameters from the code, maybe it's in the html?) - and so nothing is saved or returned from the post request.