Django Registration Not Returning Error Messages - django

Registration for this Django 4.0.3 project works well except for failure to present error messages and previously completed form field contents. In other words, registration is working with both user_form and profile_form completed and the database is updated as expected.
What is not working
If the user mismatches passwords no error is returned and page returns a blank form (I was under the impression by passing the forms back as a context dictionary that field data would be preserved - not sure what I'm missing in this regard)
The error check in forms.py to ensure a unique email is not working either (I do use forms error-checking extensively throughout the project). However, given the failure to present the password mismatch error I am inclined to believe both these symptoms share the same cause.
When registration is not valid (password mismatch or non-original email address) blank forms are returned.
The fact that forms validation is not working properly suggests that there is something inherently wrong in the register view. However, after looking at this for a couple of days I'm hoping that the bright minds of Stack Overflow will be able to point me in the right direction...
I am including all the relevant code snippets in anticipation of their being requested to support diagnosis. Given that the only element of user registration that is not working is the failure to return error messages and preserve form field contents what I've included may well be over-kill. And, I won't be surprised if I've missed something. If so, please comment with any such requests and I'll update the question.
Code Snippets
settings.py
This snippet is included to show the default password validators.
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
models.py
I have added a one-to-one relationship between the built-in User model and my own Profile model. I am aware that the User model can be extended, but opted for a Profile model (for which the Django Documentation acknowledges as acceptable). I have omitted the COUNTRY_CHOICES constant as, by my estimation, these 200+ lines of code will not support diagnosis.
from django.db import models
from django.contrib.auth.models import User
from phone_field import PhoneField
# ...
# ####################### CHOICE CONSTANTS #######################
PRONOUN_CHOICES = [
('---', '---'),
('She/her', 'She/her'),
('He/him', 'He/him'),
('They/them', 'They/them'),
('Rather not say', 'Rather not say'),
]
NOTIFICATION_PREFERENCE = [
('None', 'None'),
('Email', 'EMail'),
('Text/SMS', 'Text/SMS'),
]
# Omitted COUNTRY_CHOICES to save space
# ...
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
pronoun = models.CharField(max_length=20, choices=PRONOUN_CHOICES, default='---')
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
full_name = models.CharField(max_length=200, blank=True, null=True)
address_1 = models.CharField(max_length=100)
address_2 = models.CharField(max_length=100, blank=True, null=True)
city = models.CharField(max_length=50)
state_province_county = models.CharField(max_length=100, verbose_name='State/Province/County')
postal_zip_code = models.CharField(max_length=10, verbose_name='postal/zip code')
country = models.CharField(max_length=100, choices=COUNTRY_CHOICES, default='---')
phone = PhoneField(blank=True, help_text='Contact phone number')
notification_preference = models.CharField(
max_length=10,
choices=NOTIFICATION_PREFERENCE,
default='Email',
help_text='''If you would like to receive booking confirmation notifications from us please select your preference.'''
)
def __str__(self):
return f'{self.first_name} {self.last_name}'
forms.py
I'm using forms.py to validate for a unique email. I added this because the original approach (inspired by Corey Schafer) didn't appear to prevent duplicate email addresses.
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
# ############ Profile form validation ############
def profile_form_validation(form, form_type):
cleaned_data = super(form_type, form).clean()
if not cleaned_data.get('phone') and cleaned_data.get('notification_preference') == 'Text/SMS':
form.add_error(
'phone',
'A phone number must be entered in order to be able to receive text messages on your phone.'
)
return
# ############ Forms ############
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = [
'username',
'email',
'password1',
'password2',
]
def clean(self):
cleaned_data = super(UserRegisterForm, self).clean()
if User.objects.filter(email=cleaned_data.get('email')).exists():
self.add_error(
'email',
'That email address is already associated with an account. Please use another email address.',
)
return self.cleaned_data
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = [
'pronoun',
'first_name',
'last_name',
'address_1',
'address_2',
'city',
'state_province_county',
'postal_zip_code',
'country',
'phone',
'notification_preference',
]
def clean(self):
profile_form_validation(self, ProfileUpdateForm)
return self.cleaned_data
views.py
My instinct is that the cause of the problem is with the view to process registration.
Please note that:
I am using login() to automatically log the user in once registration is complete.
The auto-login works if the both passwords match and the email address entered is unique.
The redirect to 'events' works.
The only functionality not working is the failure to return error messages or preserve previously completed fields (excepting password1 and password2 obviously).
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import login
from .models import Profile
from .forms import (
UserRegisterForm,
ProfileUpdateForm,
)
def register(request):
if request.method == 'POST':
user_form = UserRegisterForm(request.POST)
profile_form = ProfileUpdateForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
# Process user form
user = user_form.save(commit=False)
user.save()
# Process profile form
profile_form.instance.user = user
profile_form.instance.full_name = f'{profile_form.instance.first_name} {profile_form.instance.last_name}'
profile_form.save()
# Log in user after registration
login(request, user)
messages.success(request, f'Your account (username:{username}) has been created. '
f'You are now logged in!')
return redirect('events')
else:
user_form = UserRegisterForm()
profile_form = ProfileUpdateForm()
return render(request, 'users/register.html', {'user_form': user_form, 'profile_form': profile_form})
else:
user_form = UserRegisterForm()
profile_form = ProfileUpdateForm()
return render(request, 'users/register.html', {'user_form': user_form, 'profile_form': profile_form})
urls.py
Including urls.py is probably over-kill.
from django.contrib.auth import views as auth_views
from django.urls import path
# ...
urlpatterns = [
# ...
path('register/', user_views.register, name='register'),
# ...
]
register.html
Template inclusion is also likely over-kill. However, this demonstrates the explicit use of form.errors. Again, there is no problem with template rendering (so I'm omitting base.html and the css file).
{% extends 'base.html' %}
{% load crispy_forms_filters %}
{% load crispy_forms_tags %}
{% block title %}Register{% endblock %}
{% block content %}
<section class="content-section">
<h3 class="mb-2"><strong>Registration</strong></h3>
</section>
{% if form.errors %}
<section class="content-section-danger alert-section">
<div>
<p class="alert-danger">Please review the following:</p>
<ul>
{% for key, value in form.errors.items %}
{% for error in value %}
{% if error != '' %}
<li class="alert-danger">{{ error }}</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
</div>
</section>
{% endif %}
<section class="content-section">
<div class="row">
<div class="col-lg-12 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-BlueGray">
<strong>Your Account Details</strong>
</li>
</ul>
</div>
</div>
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<div class="row">
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ user_form.username|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ user_form.email|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ user_form.password1|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ user_form.password2|as_crispy_field }}
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-lg-12 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-BlueGray">
<strong>Your Profile</strong>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.pronoun|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.first_name|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.last_name|as_crispy_field }}
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-lg-9 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.address_1|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.address_2|as_crispy_field }}
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.city|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.state_province_county|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.postal_zip_code|as_crispy_field }}
</li>
</ul>
</div>
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.country|as_crispy_field }}
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-lg-3 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.phone|as_crispy_field }}
</li>
</ul>
</div>
{% if SMS_MESSAGING_ACTIVE == 'Yes' %}
<div class="col-lg-9 pt-2 pb-2">
<ul class="list-group">
<li class="list-group-item list-group-item-white">
{{ profile_form.notification_preference|as_crispy_field }}
</li>
</ul>
</div>
{% else %}
{{ profile_form.notification_preference.as_hidden }}
{% endif %}
</div>
<div class="row">
<div class="col-lg-3">
</div>
</div>
</fieldset>
<div class="row pt-4 pb-2">
<div class="col-lg-3">
<button class="btn btn-success col-12" type="submit">Register</button>
</div>
</div>
</form>
<div class="pt-2">
<small class="text-muted">
Already have an account? Log In
</small>
</div>
</section>
{% endblock content %}

I am not sure how I missed this, but apparently I was re-creating the forms with the else branch. face palm
I'm answering the question in the chance that someone else saves time.
Corrected views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import login
from .models import Profile
from .forms import (
UserRegisterForm,
ProfileUpdateForm,
)
def register(request):
if request.method == 'POST':
user_form = UserRegisterForm(request.POST)
profile_form = ProfileUpdateForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
# Process user form
user = user_form.save(commit=False)
user.save()
# Process profile form
profile_form.instance.user = user
profile_form.instance.full_name = f'{profile_form.instance.first_name} {profile_form.instance.last_name}'
profile_form.save()
# Log in user after registration
login(request, user)
messages.success(request, f'Your account (username:{username}) has been created. '
f'You are now logged in!')
return redirect('events')
return render(request, 'users/register.html', {'user_form': user_form, 'profile_form': profile_form})
else:
user_form = UserRegisterForm()
profile_form = ProfileUpdateForm()
return render(request, 'users/register.html', {'user_form': user_form, 'profile_form': profile_form})
The moral of this story, if you're validating forms there is no need to return those forms when the forms do not return as valid!

Related

Django- Template not found

I can't seem to get my delete, edit and add review functionality working. The errors come as soon as I try to navigate to the urls I have set up. When I try and add a new review using my link on the reviews page I get the below message:
TemplateDoesNotExist at /reviews/add
I don't understand why because I have linked the url above to the template, which I have created.
The issue I have with my edit/delete views is that the url it searches for when I click the button is just /edit/ or /delete/ rather than reviews/edit/int:pk or reviews/delete/int:pk as per my urls.
I have pasted my code below, any help would be much appreciated! I have the feeling I am going to kick myself when I realise!
reviews.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid home-container">
<div class="row align-items-center">
<div class="col-sm-12 text-center mt-4">
<h2><strong>Reviews</strong></h2>
</div>
</div>
{% for review in reviews %}
<hr class="hr-1">
<div class="row featurette">
<div class="col-sm-12">
<h2 class="featurette-heading">{{ review.title }}</h2>
<p class="lead">{{ review.content }}</p>
<div class="row justify-content-between mx-1">
<p>By: {{ review.user }}</p>
<p>Created on: {{ review.created }}</p>
<p>Last Updated: {{ review.updated }}</p>
</div>
<!-- Add user authentication if -->
<div class="text-center">
<a href="edit/{{ review.id }}" class="mx-2">
<button class="positive-button mb-2">Edit</button></a>
<a href="delete/{{ review.id }}" class="mx-2 mb-2">
<button class="negative-button">Delete</button></a>
</div>
</div>
</div>
{% endfor %}
<div class="row">
<div class="col-sm-12 text-center py-4">
{% if user.is_authenticated %}
<a href="{% url 'home:add_review' %}">
<button class="positive-button-lg">Add a review</button>
</a>
{% else %}
<p>If you would like to add your own review, please login or sign up if you haven't already!</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
add_review.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{{ review_form }}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
</div>
</div>
{% endblock %}
views.py:
from django.shortcuts import render
from django.views import View
from django.urls import reverse_lazy
from django.views.generic import UpdateView, DeleteView
from .models import Reviews
from .forms import ReviewForm
def home(request):
''' Returns the home page.'''
return render(request, 'home/index.html')
def reviews(request):
''' Returns the reviews page.'''
serialized_reviews = []
reviews = Reviews.objects.all()
for review in reviews:
serialized_reviews.append({
"title": review.title,
"content": review.content,
"user": review.user,
"created": review.created,
"updated": review.updated,
})
context = {
"reviews": serialized_reviews
}
print(serialized_reviews)
return render(request, 'home/reviews.html', context)
class AddReview(View):
'''View which allows the user to add a new review.'''
def get(self, request, *args, **kwargs):
review = Reviews
review_form = ReviewForm
context = {
'review': review,
'review_form': review_form,
'user': review.user,
'title': review.title,
'content': review.content,
}
return render(request, 'add_review.html', context)
def post(self, request, *args, **kwargs):
review_form = ReviewForm(data=request.POST)
if review_form.is_valid():
obj = review_form.save(commit=False)
obj.user = request.user
obj.save()
return redirect("home:reviews")
class DeleteReview(DeleteView):
'''View which allows the user to delete the selected review.'''
model = Reviews
template_name = 'delete_review.html'
success_url = reverse_lazy('reviews')
class EditReview(UpdateView):
'''View which allows the user to edit the selected review.'''
model = Reviews
template_name = 'edit_review.html'
fields = ['title', 'content']
urls.py:
from django.urls import path
from . import views
app_name = 'home'
urlpatterns = [
path('', views.home, name='home'),
path('reviews', views.reviews, name='reviews'),
path('reviews/add', views.AddReview.as_view(), name='add_review'),
path('reviews/delete/<int:pk>', views.DeleteReview.as_view(), name='delete_review'),
path('reviews/edit/<int:pk>', views.EditReview.as_view(), name='edit_review'),
]
The main difference is my app name, which is 'core'. Also, I forgot to add the content field to the model, but that is easily done, the form will just handle it as soon as you do the migration. (except on list.html)
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
class Reviews(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
title = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=timezone.now())
updated_at = models.DateTimeField(auto_now=timezone.now())
forms.py
from django import forms
from core.models import Reviews
class ReviewsForm(forms.ModelForm):
class Meta:
model = Reviews
fields = '__all__'
views.py
from core.models import Reviews
from core.forms import ReviewsForm
from django.shortcuts import render, redirect
def list_reviews(request):
reviews = Reviews.objects.all()
context = {
"reviews": reviews
}
return render(request, 'reviews/list.html', context)
def add_review(request):
if request.method == 'POST':
form = ReviewsForm(request.POST)
if form.is_valid():
form.save()
return redirect('/reviews/')
else:
form = ReviewsForm()
context = {
'form': form
}
return render(request, 'reviews/detail.html', context)
def edit_review(request, pk):
if request.method == 'POST':
form = ReviewsForm(request.POST)
if form.is_valid():
obj = Reviews.objects.get(id=pk)
obj.title = form.cleaned_data['title']
obj.user = form.cleaned_data['user']
obj.save()
return redirect('/reviews/')
else:
obj = Reviews.objects.get(id=pk)
form = ReviewsForm(instance=obj)
context = {
'form': form
}
return render(request, 'reviews/detail.html', context)
def delete_review(request, pk):
obj = Reviews.objects.get(id=pk)
obj.delete()
return redirect('/reviews/')
urls.py
from django.urls import path
import core.views as views
app_name = 'core'
urlpatterns = [
path('reviews/', views.list_reviews, name='list-reviews'),
path('reviews/add', views.add_review, name='add-review'),
path('reviews/edit/<int:pk>/', views.edit_review, name='edit-review'),
path('reviews/delete/<int:pk>/', views.delete_review, name='delete-review'),
]
list.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid home-container">
<div class="row align-items-center">
<div class="col-sm-12 text-center mt-4">
<h2><strong>Reviews</strong></h2>
</div>
</div>
{% for review in reviews %}
<hr class="hr-1">
<div class="row featurette">
<div class="col-sm-12">
<h2 class="featurette-heading">{{ review.title }}</h2>
<p class="lead">{{ review.content }}</p>
<div class="row justify-content-between mx-1">
<p>By: {{ review.user }}</p>
<p>Created on: {{ review.created_at }}</p>
<p>Last Updated: {{ review.updated_at }}</p>
</div>
<!-- Add user authentication if -->
<div class="text-center">
<a href="{% url 'core:edit-review' pk=review.id %}" class="mx-2">
<button class="positive-button mb-2">Edit</button></a>
<a href="{% url 'core:delete-review' pk=review.id %}" class="mx-2 mb-2">
<button class="negative-button">Delete</button></a>
</div>
</div>
</div>
{% endfor %}
<div class="row">
<div class="col-sm-12 text-center py-4">
{% if user.is_authenticated %}
<a href="{% url 'core:add-review' %}">
<button class="positive-button-lg">Add a review</button>
</a>
{% else %}
<p>If you would like to add your own review, please login or sign up if you haven't already!</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
detail.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{% csrf_token %}
<table>
{{ form }}
</table>
<button type="submit" class="btn btn-primary btn-lg">Save</button>
</form>
</div>
</div>
{% endblock %}
According to your urls, It is a review/edit/<int:pk>.
So you must add same thing in href tag.
Change this:
<a href="edit/{{ review.id }}"
To this:
<a href="review/edit/{{ review.id }}"
That's why you are getting that error
I've fixed it, firstly the path in my add_review view was wrong, which I have amended and it now works (thanks Ivan).
I also was not actually bringing the ID through on my 'reviews' view in the first place, so when following the links on my edit and review buttons, it didn't know what I meant by 'id', as I hadn't specified what that was in the view context.
Thanks for the help all!
I think you're writing in your urls the wrong way, like this below your div text-center:
<a href="edit/{{ review.id }}" class="mx-2">
It should be:
<a href="{% url 'yourappname:edit' review.id %}">

django form errors not showing on template

I'm using the basic django registration form and I'm not getting any errors displayed. I've seen a bunch of answers and nothing is working for me. I'm not sure if it's because I have custom css for the page or bootstrap or something else. Basically how do I display the errors in this particular case.
Here's my form:
<div class="form-content">
<h1>Sign Up</h1>
{% if user.is_authenticated == False %}
<form method="POST">
{% csrf_token %} {{form.as_p}}
<button class="btn form-btn">Sign Up</button>
<h4><span>or</span></h4>
<a
class="btn google-btn"
href="{% provider_login_url 'google' %}"
role="button"
style="text-transform: none; width: 100%"
>
<img
width="20px"
style="margin-bottom: 3px; margin-right: 5px"
alt="Google sign-in"
src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/512px-Google_%22G%22_Logo.svg.png"
/>
Sign up with Google
</a>
</form>
{% else %}
<p>You're already registered...</p>
{% endif %}
</div>
Here's my view:
class UserRegistration(generic.CreateView):
form_class = RegisterForm
template_name = 'registration/registration.html'
def form_valid(self, form):
user = form.save()
form.registration_notification()
login(self.request, user, backend='django.contrib.auth.backends.ModelBackend')
return redirect(self.request.GET.get('next'))
and form:
class RegisterForm(UserCreationForm):
email = forms.EmailField()
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2')
def registration_notification(self):
email = self.cleaned_data['email']
username = self.cleaned_data['username']
if self.is_valid():
registration_notification_task.delay(email, username)
I'm not sure where to return the errors or where to validate the form and no answers for other questions have helped my situation. Now when I submit an invalid form there are no errors the page just doesn't submit. There's not even an error in the network tab so it's probably happening on the html side.
Updating my post following comments below:
**forms.py** (dont forget the import bit)
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
class RegisterForm(UserCreationForm):
class Meta:
model = User
fields = ["username", "email", "password1", "password2",]
views.py
def register_user(request):
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
new_user = form.save()
new_user = authenticate(username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],)
login(request, new_user)
messages.success(request,("Registration succesful!"))
return HttpResponseRedirect("/home")
else:
form = RegisterForm()
return render(request,'main/registration/register_user.html',{'form':form})
registration template
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-5 mx-auto">
<div id="second">
<div class="myform form ">
<div class="logo mb-3">
<div class="col-md-12 text-center">
<h1 >Signup</h1>
</div>
</div>
<form method="POST" action = "{% url 'register_user' %}" class="form-group">
{% csrf_token %}
{{ form| crispy }}
<div class="col-md-12 text-center mb-3">
<button type="submit" class=" btn btn-block mybtn btn-primary tx-tfm">Let's do it!</button>
</div>
<div class="col-md-12 ">
<div class="form-group">
<p class="text-center">Already have an account?</p>
</div>
</div>
</div>
</form>
</div>
</div>
{% endblock %}

Validation inactive user Django

I looking for a resolving of my issue.
I have custom User model:
class User(AbstractUser):
username = models.CharField(max_length=150, unique=True, blank=False, null=False)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
password = models.CharField(max_length=150, blank=False)
email = models.EmailField(unique=True, blank=False)
date_create = models.DateTimeField(auto_now_add=True)
address = models.CharField(blank=True, max_length=128)
phone = PhoneNumberField(unique=True)
photo = models.ImageField(upload_to='images/', blank=True)
is_active = models.BooleanField(default=True)
In my app I have e-mail-confirmation. When I create user I hit the "is_active=False". When user activate account then flag "is_active=True". Everything works good.
But when INactive user tries to log in I wanna get message from Django in Login form.
Django has it(source code):
def confirm_login_allowed(self, user):
if not user.is_active:
raise ValidationError(
self.error_messages['inactive'],
code='inactive',
)
But doesn't work for me.
Update: When inactive user tried to log in I get same message as user with incorrect username or password.
I tried to override AuthenticationForm:
User = get_user_model()
class CustomAuthenticationForm(AuthenticationForm):
class Meta: # tried with Meta and without
model = User
def confirm_login_allowed(self, user):
if not user.is_active:
raise forms.ValidationError('There was a problem with your login.')
View:
class CustomLoginView(SuccessMessageMixin, LoginView):
form_class = CustomAuthenticationForm
success_url = reverse_lazy('home')
success_message = "You was logged in successfully"
url:
path('login/', CustomLoginView.as_view(), name='login'),
Update, templates base and login:
<!doctype html>
{% load static %}
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx"
crossorigin="anonymous"></script>
{% block mystyle %}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark justify-content-center">
<a class="navbar-brand" href="#">Site</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup"
aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<a class="nav-link" href="{% url 'home' %}">Home</a>
{% if user.is_authenticated %}
<a class="nav-link" href="{% url 'cabinet' %}">Cabinet</a>
<a class="nav-link" href="{% url 'logout' %}">LogOut</a>
{% else%}
<a class="nav-link" href="{% url 'signup' %}">SignUp</a>
<a class="nav-link text-right" href="{% url 'login' %}">LogIn</a>
{% endif %}
</div>
</div>
</nav>
{% if messages %}
{% for message in messages %}
<div class="alert alert-success">{{ message }}</div>
{% endfor %}
{% endif %}
{% block content %}
{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
{% block title %}Log In{% endblock %}
{% block content %}
<h1 class="row justify-content-center p-4">Log In</h1>
<div class="row justify-content-center">
<div class="col-4">
<form autocomplete="off" method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="container p-2">
Forgot your password?
</div>
<div class="container p-2">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
{% endblock %}
Could someone help me? Thanks.
I understood it from point of security. I resolved it just override ModelBackend
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class CustomModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password): # here (remove 'and self.user_can_authenticate(user):')
return user
Settings
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'accounts.backends.CustomModelBackend',
]

how can I access userprofile from another user?

I need some help when I create a user and user profile accordingly and when I try to access to any user by another user the request turns me on the request I work on not the real user, although, I'm using the slug to specify what the user I click on it maybe I can not explain what happens to me exactly for more explanation, please click on that video to show what I mean: https://www.youtube.com/watch?v=MzSo0ay2_Xk&feature=youtu.be
accounts app
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.template.defaultfilters import slugify
CHOICE = [('male', 'male'), ('female', 'female')]
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100, unique=True, blank=True)
overview = models.TextField(editable=True, blank=True, default='You have no an Overview yet')
city = models.CharField(max_length=20, blank=False)
phone = models.IntegerField(default=0, blank=True)
sex = models.CharField(max_length=10, default='male', choices=CHOICE)
skill = models.CharField(max_length=100, default='You have no skills yet')
logo = models.ImageField(upload_to='images/', default='images/default-logo.jpg', blank=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
self.slug = slugify(self.user)
super().save(*args, **kwargs)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(receiver=create_profile, sender=User)
view.py
class ViewProfile(UpdateView):
queryset = UserProfile.objects.all()
template_name = 'accounts/profile.html'
form_class = UpdateInfoForm
slug_field = 'slug'
slug_url_kwarg = 'user_slug'
def get_success_url(self):
return reverse_lazy('accounts:view_profile', kwargs={'user_slug': self.request.user.userprofile.slug})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_prof = UserProfile.objects.get(user=self.request.user)
context['user_prof'] = user_prof
context['get_favourite'] = User.objects.get(username=self.request.user.username).favorite.all()
return context
def form_valid(self, form):
form.instance.user_slug = self.request.user.userprofile.slug
self.object = form.save()
return super().form_valid(form)
profile.html
{% extends 'base.html' %}
{% block title %} {{ user.first_name }} {{ user.last_name }} Profile {% endblock %}
{% block body %}
<!-- User Profile Section -->
{% if user.is_authenticated %}
<div class="profile">
<div class="container-fluid">
<div class="col-md-1">
<div class="thumbnail">
<div class="row">
<div class="col-xs-12">
<!-- Profile View Section -->
<div class="logo-image text-center">
{% if user.userprofile.logo %}
<div class="my-image">
{% if request.user.username == user.userprofile.slug %}
<a href="{% url 'accounts:user_image' user.userprofile.slug %}">
<img class="img-responsive" src="{{ user.userprofile.logo.url }}">
</a>
<span>
<a href="{% url 'accounts:add_avatar' user.userprofile.slug %}" class="fa fa-camera fa-1x text-center">
<p>Upload Image</p>
</a>
</span>
{% endif %}
</div>
{% else %}
{% load static %}
<div class="my-image">
<img class="img-responsive img-thumbnail" src="{% static 'index/images/default-logo.jpg' %}">
<span>
<a href="{% url 'accounts:add_avatar' user.userprofile.slug %}" class="fa fa-camera fa-1x text-center">
<p>Upload Image</p>
</a>
</span>
</div>
{% endif %}
<h4>{{ user.first_name }} {{ user.last_name }}</h4>
</div>
</div>
<div class="col-xs-12">
<div class="caption">
<ul class="nav nav-pills nav-stacked">
<li role="presentation" class="active">Overview</li>
<li role="presentation" class="">Personal Information</li>
<li role="presentation" class="">Skills</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Information Sections -->
<div class="col-md-8 col-md-offset-3 information">
<div class="overview show" id="overview">
<h2 class="line">Overview</h2>
<p class="lead">{{ user.userprofile.overview }}</p>
<a data-placement="bottom" title="update overview" class="fa fa-edit" data-toggle="modal" data-tooltip="tooltip" data-target=".overview_info"></a>
</div>
<div class="personal-info" id="personal-information">
<h2 class="line">Personal Information</h2>
<p class="lead">City: {{ user.userprofile.city }}</p>
<p class="lead">Phone Number: 0{{ user.userprofile.phone }}</p>
<p class="lead">Sex: {{ user.userprofile.sex }}</p>
<a data-placement="bottom" title="update personal information" class="fa fa-edit" data-toggle="modal" data-tooltip="tooltip" data-target=".personal_info"></a>
</div>
<div class="skill" id="my-skills">
<h2 class="line">Skills:</h2>
<p class="lead">{{ user.userprofile.skill }}</p>
<a data-placement="bottom" title="update skills" class="fa fa-edit" data-toggle="modal" data-tooltip="tooltip" data-target=".skills"></a>
</div>
</div>
<!-- get all questions -->
{% if user_prof.userasking_set.all %}
<div class="col-md-8 col-md-offset-3 user_questions">
<h2 class="line">All Questions You Asked</h2>
{% for questions in user_prof.userasking_set.all %}
<p>{{ questions.title }}</p>
{% endfor %}
</div>
{% endif %}
<!-- get favourites -->
{% if get_favourite %}
<div class="col-md-8 col-md-offset-3 user_questions">
<h2 class="line">Favourites</h2>
{% for fav in get_favourite %}
<p>{{ fav.title }}</p>
{% endfor %}
</div>
{% endif %}
</div>
{% include 'accounts/information_form.html' %}
</div>
{% include 'base_footer.html' %}
{% endif %}
{% endblock %}
self.request.user refers to the currently logged in user. That is why you are getting the same result for all users.
To get what you want, you need to make the following change in your views:
user_prof = UserProfile.objects.get(pk=self.kwargs['pk'])
But also, I'm not sure why you are using an UpdateView when you simply want to display objects? You should use TemplateView instead.

How do i solve UNIQUE constraint failed: auth_user.username problem in Django

I am brand new to Django.
I made a register form.
One time out of two, when i try to register a new user i have an exception "auth_user.username"
it seems there is no rule, it can works many times in a row and with new user registration i have the error!
Here is my form.py
from django.contrib.auth.forms import UserCreationForm,AuthenticationForm
from django.contrib.auth.models import User
from bootstrap_modal_forms.mixins import PopRequestMixin, CreateUpdateAjaxMixin
from django import forms
class CustomUserCreationForm(PopRequestMixin, CreateUpdateAjaxMixin,
UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
def clean_email(self):
if User.objects.filter(email=self.cleaned_data['email']).exists():
raise forms.ValidationError("the given email is already registered")
return self.cleaned_data['email']
'''
views.py
enter code here
from django.urls import reverse_lazy
from bootstrap_modal_forms.generic import BSModalCreateView,BSModalLoginView
from .forms import CustomUserCreationForm,CustomAuthenticationForm
class SignUpView(BSModalCreateView):
form_class = CustomUserCreationForm
template_name = 'signup.html'
success_message = 'Success: Sign up succeeded. You can now Log in.'
success_url = reverse_lazy('index')
signup.html
enter code here
{% load widget_tweaks %}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-
q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
body data-spy="scroll" data-target=".site-navbar-target" data-offset="300">
<form method="post" action="">
{% csrf_token %}
<div class="modal-header">
<h3 class="modal-title">Register</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
<div class="{% if field.errors %} invalid{% endif %}">
{% for error in field.errors %}
<p class="help-block" style="color:red">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
Register
THANK YOU
I remember two ways we can accomplish that:
Override the User model's save method and only try to save if the object does not exist:
def save(self, *args, **kwargs):
if not User.objects.filter(name=self.name).first():
super(User, self).__init__(*args, **kwargs)
Create your custom model and inherit from User, and drop the unique constraint:
class CustomUser(User):
username = models.CharField(_("User name"), max_length=30, blank=False)
This way you have more control of your validations.