I just started learning Django and Python some weeks back. Working on a project sign up page, everything works perfectly except that form errors are not displaying on the form itself but redirected to a debug error page with the below
ValidationError at /register/
['Username exists']
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
Django Version: 3.2.5
Exception Type: ValidationError
Exception Value:
['Username exists']
During a new user profile registration, i am checking if the username used to register already exists or not and if it exists, i want to display an error to user that Username already exists.
Please see my code below:
forms.py
class RegistrationForm(forms.Form):
first_name = forms.CharField(label='First Name')
last_name = forms.CharField(label='Last Name')
username = forms.CharField(label='Username')
password = forms.CharField(
label='Password', widget=forms.PasswordInput(), min_length=8)
password_confirm = forms.CharField(
label='Confirm Password', widget=forms.PasswordInput())
email_address = forms.EmailField(label='Email')
phone_number = PhoneNumberField(label='Phone Number')
whatsapp_number = PhoneNumberField(label='WhatsApp Number', required=False)
COUNTRY_CHOICES = [
('', 'Choose...'),
]
country = forms.ChoiceField(label='Country', choices=COUNTRY_CHOICES)
referral_id = forms.CharField(label='Referral ID', required=False)
license_agreement = forms.BooleanField(
label='I agree to all the Terms and Conditions')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'create-account-form'
self.helper.form_action = 'register'
self.helper.form_show_errors = True
self.helper.layout = Layout(
Row(
Column('first_name'),
Column('last_name'), css_class='g-2'
),
Row(
Column(
PrependedText('username', '#')
),
Column('country'), css_class='g-2'
),
Row(
Column('password'),
Column('password_confirm'),
Column('referral_id'),
css_class='g-2'
),
Row(
Column('phone_number'),
Column('whatsapp_number'),
Column('email_address'), css_class='g-2'
),
Row('license_agreement'),
Row(Submit('submit', 'Create Account'))
)
def check_username(self):
data = self.cleaned_data['username']
if User.objects.filter(username__iexact=data).exists():
raise ValidationError('Username exists')
return data
def compare_passwords(self):
password1 = self.cleaned_data['password']
password2 = self.cleaned_data['password_confirm']
if password2 != password1:
raise ValidationError('Password does not match')
return password1
views.py
def reg_form(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
username = form.check_username()
password = form.compare_passwords()
email = form.cleaned_data['email_address']
user = User.objects.create_user(
username=username, email=email, password=password)
user.first_name = first_name
user.last_name = last_name
user.save()
user_info = UserInfo()
user_info.user = user
user_info.linked_user = user.username
user_info.phone_number = form.cleaned_data['phone_number']
user_info.whatsapp_number = form.cleaned_data['whatsapp_number']
user_info.country = form.cleaned_data['country']
user_info.referral_id = form.cleaned_data['referral_id']
user_info.save()
login(request, user)
return redirect(reverse('dashboard'), permanent=True)
else:
form = RegistrationForm()
return render(request, 'office/reg_form_hx.html', {'form': form})
template
{% extends './base.html' %}
{% block main %}
{% load crispy_forms_tags %}
{% crispy form %}
{% endblock main %}
I figured this out.
I was supposed to implement the form clean() method or the clean_fieldname() method for a specific field.
It should have been clean_username() and not check_username() in the forms.py file.
Thank you.
Related
I made a signup form and a signup view in the Django project. But it seems that 'create_user' does not work. There is no error. Signup view just sends the browser to Home without creating a new user object
The user model is using email as a username.
I tried to do this with ModelForms but it was the same.
I don't know why happens this.
users/forms.py
class StudentSignUpForm(forms.Form):
first_name = forms.CharField()
last_name = forms.CharField()
email = forms.EmailField(
widget=forms.EmailInput(attrs={"placeholder": "Enter your emaill adress"})
)
password = forms.CharField(
widget=forms.PasswordInput(attrs={"placeholder": "Enter the Password"})
)
password_confirm = forms.CharField(
widget=forms.PasswordInput(attrs={"placeholder": "Confirm the Password"})
)
def clean_email(self):
email = self.cleaned_data.get("email")
try:
models.User.objects.get(email=email)
raise forms.ValidationError("This email already exists.")
except models.User.DoesNotExist:
return email
def clean_password_confirm(self):
password = self.cleaned_data.get("password")
password_confirm = self.cleaned_data.get("password_confirm")
if password != password_confirm:
raise forms.ValidationError("Password confirmation does not match.")
else:
return password
def save(self):
first_name = self.cleaned_data.get("first_name")
last_name = self.cleaned_data.get("last_name")
email = self.cleaned_data.get("email")
password = self.cleaned_data.get("password")
user = models.User.objects.create_user(email, password)
user.first_name = first_name
user.last_name = last_name
user.save()
users/views.py
class StudentSignupView(FormView):
template_name = "users/student_signup.html"
form_class = forms.StudentSignUpForm
success_url = reverse_lazy("core:home")
def form_vaild(self, form):
form.save()
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
user = authenticate(self.request, username=email, password=password)
if user is not None:
login(self.request, user)
return super().form_valid(form)
templates/users/student_signup.html
{% extends "base.html" %}
{% block page_title %}
Student Sign up
{% endblock page_title %}
{% block movie_search_bar %}
{% endblock movie_search_bar %}
{% block people_search_bar %}
{% endblock people_search_bar %}
{% block content %}
<form method="post" action="{% url 'users:student_signup' %}">
{% csrf_token %}
{{form.as_p}}
<button>Sign up</button>
</form>
{% endblock content%}
users/urls.py
from django.urls import path
from users import views as user_views
app_name = "users"
urlpatterns = [
path("students/", user_views.StudentList.as_view(), name="list"),
path(
"students/<int:pk>", user_views.StudentProfile.as_view(), name="student_profile"
),
path("students/search/", user_views.SearchView.as_view(), name="search"),
path("users/login/", user_views.LoginView.as_view(), name="login"),
path("users/logout/", user_views.log_out, name="logout"),
path("users/signup/", user_views.sign_up, name="signup"),
path(
"users/signup/student",
user_views.StudentSignupView.as_view(),
name="student_signup",
),
]
users/models.py
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
from django.db import models
class CustomUserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError("Users require an email field")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", False)
extra_fields.setdefault("is_superuser", False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
if extra_fields.get("is_staff") is not True:
raise ValueError("Superuser must have is_staff=True.")
if extra_fields.get("is_superuser") is not True:
raise ValueError("Superuser must have is_superuser=True.")
return self._create_user(email, password, **extra_fields)
class User(AbstractUser):
"""User Model Definition"""
SCHOOL_ACCA_ROMA = "acccademia_belle_arti_di_roma"
SCHOOL_CHOICES = ((SCHOOL_ACCA_ROMA, "Accademia Belle Arti di Roma"),)
ACCOUNT_TYPE_STUDENT = "student"
ACCOUNT_TYPE_PUBLIC = "public"
ACCOUNT_TYPE_CHOICES = (
(ACCOUNT_TYPE_STUDENT, "Studente"),
(ACCOUNT_TYPE_PUBLIC, "Publico"),
)
username = None # email을 username으로 사용하기 위해 Abspython manage.py migratetractUser의 username을 none으로 override.
email = models.EmailField(
_("email address"), unique=True
) # _ 는 ugettext_lazy()의 별칭. 언어설정에 따라 출력되는 문자열을 변환해주는 함수다.
USERNAME_FIELD = "email" # email을 username처럼 사용하기.
REQUIRED_FIELDS = (
[]
) # AbsractUser에는 email이 Required로 잡혀있으나 USERNAME_FIELD로 사용되는 필드는 REQUIRED에 있으면 안된다.
school = models.CharField(
_("accademia"), choices=SCHOOL_CHOICES, max_length=50, null=True, blank=True
)
avatar = models.ImageField(upload_to="user_avatars", null=True, blank=True)
biography = models.TextField(_("biography"), null=True, blank=True)
account_type = models.CharField(
_("tipo d'account"),
choices=ACCOUNT_TYPE_CHOICES,
max_length=50,
null=True,
blank=True,
)
objects = CustomUserManager()
def __str__(self):
return self.email
In an extended user model with User and Profile created together. The user and related profile(Customer) is created but two fields 'email'(user email) field and 'photo'(image field) is not saved into database. Appreciate some fix:
views.py
def customer_register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
profile_form = CustomerProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# Set the chosen password
new_user.set_password(
user_form.cleaned_data['password'])
# Save the User object
new_user.save()
# Create the customer profile
customer = profile_form.save(commit=False)
customer.user = new_user
customer.save()
#Customer.objects.create(user=new_user,date_of_birth=customer.date_of_birth, photo=customer.photo, pincode=customer.pincode)
return render(request,
'registration/register_done.html',
{'new_user': new_user})
else:
messages.error(request, 'Error in creating your profile')
else:
user_form = UserRegistrationForm()
profile_form = CustomerProfileForm()
Forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(label='Password',
widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat password',
widget=forms.PasswordInput)
email = forms.EmailField(label='email', widget=forms.EmailInput, required=True)
class Meta:
model = User
fields = ['username', 'first_name', 'email']
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('Passwords don\'t match.')
return cd['password2']
def clean_email(self):
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Email exists. Please change email")
class CustomerProfileForm(forms.ModelForm):
pincode = INZipCodeField(label="PIN")
date_of_birth = forms.DateField(widget=forms.DateInput(format='%d/%m/%Y'), input_formats=('%d/%m/%Y',))
photo = forms.ImageField()
class Meta:
model = Customer
fields = ['pincode','date_of_birth','photo']
I figured out the email id issue was in the form, form had to return the email in the email validation function
clean_email(self):
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Email exists. Please change email")
return email
In the views I had to add request for files(image) along with form:
profile_form = CustomerProfileForm(request.POST, request.FILES or None)
The image issue was in the registration html template. I updated the form to enctype "multipart/form-data" to take get image inputs
<form method="post" enctype="multipart/form-data" action="{% url 'customer_register' %}">
{% csrf_token %}
When I am trying to register, I'm getting an error:
Forbidden (403)
CSRF verification failed. Request aborted.
My Code:
#csrf_protect
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST, request.FILES)
if form.is_valid():
first_name = form.cleaned_data.get("firstname")
last_name = form.cleaned_data.get("lastname")
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = User.objects.create_user(username=username,password=password)
user.first_name = first_name
user.last_name = last_name
user.set_password(password)
user.is_active = True
user.save()
return HttpResponseRedirect('/home/')
else:
form = RegistrationForm()
return render_to_response('registration/registerHome.html',dict(form=form,
context_instance=RequestContext(request) ) )
my form.py
class RegistrationForm(forms.Form):
"""
A registration form to create normal user.
"""
firstname = forms.RegexField(regex=r'^\[a-zA-Z]+$',
widget=forms.TextInput(attrs={ 'required':True,
'max_length':30,
'autocomplete':'off',
'class':'form-control input-sm',
'placeholder':'First Name' }),
error_messages={ 'invalid': _("Only alphabets are allowed.") }
)
lastname = forms.RegexField(regex=r'^\[a-zA-Z]+$',
widget=forms.TextInput(attrs={ 'required':True,
'max_length':30,
'autocomplete':'off',
'class':'form-control input-sm',
'placeholder':'Last Name' }),
error_messages={ 'invalid': _("Only alphabets are allowed.") }
)
username = forms.RegexField(regex=r'^\w+$',
widget=forms.TextInput(attrs={'required':True,
'max_length':30,
'autocomplete':'off',
'class':'form-control input-sm',
'placeholder':'username'}),
error_messages={ 'invalid': _("Only [a-z A-Z 0-9 _] are allowed.") }
)
password = forms.CharField(widget=forms.PasswordInput(attrs={
'required':True,
'max_length':30,
'autocomplete':'off',
'class':'form-control input-sm',
'placeholder':'password',
'render_value':False })
)
def clean_username(self):
try:
user = User.objects.get(username__iexact=self.cleaned_data['username'])
except User.DoesNotExist:
return self.cleaned_data['username']
raise forms.ValidationError(_("Username already exists."))
class Meta:
model = User
my template.html
<form action="." method="post" role="form" id="register-form">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" />
</form>
Someone, please help me, why I'm getting an error. I am trying to solve this problem for 1 week and still getting the error. Please help me.
You should use render and add else
Then do like
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST, request.FILES)
if form.is_valid():
first_name = form.cleaned_data.get("firstname")
last_name = form.cleaned_data.get("lastname")
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = User.objects.create_user(username=username,password=password)
user.first_name = first_name
user.last_name = last_name
user.set_password(password)
user.is_active = True
user.save()
return HttpResponseRedirect('/home/')
else:
return render(request, 'registration/registerHome.html',dict(form=form)))
else:
form = RegistrationForm()
return render(request, 'registration/registerHome.html',dict(form=form)))
You don't need to use the #csrf_protect decorator as long as the csrf middleware is added.The Middleware gives you blanket protection on all views - adding the decorator is redundant. The Django docs recommend using the Middleware over the decorator as it provides better protection.
Try after removing the decorator.
Try something like this. I remember sometime ago I had the same problem and declaring the c dictionary and passing it to the render_to_response solved my problem.
#csrf_protect
def register(request):
if request.method == 'POST':
# do your post stuff here
pass
else:
c = {}
c['form'] = RegistrationForm()
c['context_instance'] = RequestContext(request)
return render_to_response('registration/registerHome.html',c )
Try using https://docs.djangoproject.com/en/1.11/topics/http/shortcuts/#render
from django.shortcuts import render
#csrf_protect
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST, request.FILES)
if form.is_valid():
first_name = form.cleaned_data.get("firstname")
last_name = form.cleaned_data.get("lastname")
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = User.objects.create_user(username=username,password=password)
user.first_name = first_name
user.last_name = last_name
user.set_password(password)
user.is_active = True
user.save()
return HttpResponseRedirect('/home/')
else:
form = RegistrationForm()
return render(request, 'registration/registerHome.html',dict(form=form) ) )
I have a problem with adding new custom user to the database. I know thare's some threads about it on the internet but I couldn't find solution for my problem. After hitting "Submit" button in registration page which template is here:
{% extends 'strona/Main.html' %}
{% block body %}
< form action="" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }}
< /br >
{{ field }}
< /br >
< /br >
{% endfor %}
< button type="submit" class="btn btn-success">Submit</button >
< /form >
{% endblock %}
it keeps saying that: "Cannot assign "< SimpleLazyObject: < django.contrib.auth.models.AnonymousUser object at 0x038B5A70 >>": "SUser.user" must be a "User" instance."
Source Codes:
VIEWS.PY
class RegPanelView(View):
panel = RegPanel
template_name = 'strona/RegistrationTemp.html'
registration = None
def get(self, request):
form = self.panel(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
# form = self.panel(data=request.POST)
form = self.panel(request.POST)
if form.is_valid():
# user = form.save(commit=False)
# username = form.cleaned_data['username']
password1 = form.cleaned_data['password1']
password2 = form.cleaned_data['password2']
if password1 == password2:
newuser = form.save(commit=False)
newuser.user = request.user
newuser.save()
return redirect('strona:index')
return render(request, self.template_name, {'form': form})
MODELS.PY
class SUser(models.Model):
# User = user_model()
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length=200)
# last_login = models.DateTimeField(blank=True)
# is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
relations = models.ManyToManyField('self')
# is_anonymous = False
# is_authenticated = True
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ('', )
FORMS.PY
class RegPanel(UserCreationForm):
# password = forms.CharField(max_length=16, widget=forms.PasswordInput)
# first_name = forms.CharField(max_length=100, required=False)
# last_name = forms.CharField(max_length=100, required=False)
# is_staff = forms.BooleanField(required=False)
# birthday = forms.DateField(required=False)
class Meta:
model = SUser
fields = ['username', 'is_staff', 'first_name', 'last_name']
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
# user.set_password(self.cleaned_data["passwosrd1"])
if commit:
user.set_password(self.cleaned_data["password1"])
user.save()
# if commit:
# user.save()
return user
SETTINGS.PY:
AUTH_USER_MODEL = 'auth.User'
EDIT
FULL ERROR TRACEBACK:
File
"C:\Users\Dawid\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django-1.10.3-py3.5.egg\django\core\handlers\exception.py"
in inner
39. response = get_response(request)
File
"C:\Users\Dawid\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django-1.10.3-py3.5.egg\django\core\handlers\base.py"
in _get_response
187. response = self.process_exception_by_middleware(e, request)
File
"C:\Users\Dawid\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django-1.10.3-py3.5.egg\django\core\handlers\base.py"
in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File
"C:\Users\Dawid\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django-1.10.3-py3.5.egg\django\views\generic\base.py"
in view
68. return self.dispatch(request, *args, **kwargs)
File
"C:\Users\Dawid\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django-1.10.3-py3.5.egg\django\views\generic\base.py"
in dispatch
88. return handler(request, *args, **kwargs)
File "C:\Users\Dawid\PycharmProjects\Zadanie\strona\views.py" in post
97. newuser.user = request.user
File
"C:\Users\Dawid\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django-1.10.3-py3.5.egg\django\db\models\fields\related_descriptors.py"
in set
211. self.field.remote_field.model._meta.object_name,
Exception Type: ValueError at /index/register/ Exception Value: Cannot
assign "< SimpleLazyObject: >": "SUser.user" must be a "User" instance.
Please could someone help me out?
Kind regards.
Django lazy loads request.user so that it can be either User or AnonymousUser depending on the authentication state.
if request.user.is_authenticated(): #then request.user will be `User` instance
newuser = form.save(commit=False)
newuser.user = request.user
newuser.save()
I've been trying everything, but I can't figure out why it's not showing-up. I searched everywhere on this site with no luck. The button shows up but when I click than it give me a TypeError at get_profile, saying:
Exception Value:
get_profile() got an unexpected keyword argument 'username'
Here's my code:
models.py
class CustomUser(AbstractBaseUser):
email = models.EmailField('email address', unique=True, db_index=True)
username = models.CharField('username', max_length=50, unique=True, db_index=True)
first_name = models.CharField(max_length=50, blank=False)
last_name = models.CharField(max_length=50, blank=False)
joined = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __unicode__(self):
return self.username
forms.py
from django import forms
from apps.accounts.models import CustomUser
class RegistrationForm(forms.ModelForm):
email = forms.EmailField(widget=forms.TextInput, label='email')
username = forms.CharField(widget=forms.TextInput, label='username')
password1 = forms.CharField(widget=forms.PasswordInput, label='Enter your password')
password2 = forms.CharField(widget=forms.PasswordInput, label='Re-type your password')
first_name = forms.CharField(widget=forms.TextInput, label='First Name')
last_name = forms.CharField(widget=forms.TextInput, label='Last Name')
class Meta:
model = CustomUser
fields = ['email', 'username', 'password1', 'password2', 'first_name', 'last_name']
def clean(self, password1, password2):
cleaned_data = super(RegistrationForm, self).clean()
if password1 in self.cleaned_data and password2 in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords don't match. Please enter both fields again")
return self.cleaned_data
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
views.py
def register(request):
"""
User Registration View
"""
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
CustomUser = form.save()
CustomUser.save()
return redirect('home.html')
else:
form = RegistrationForm()
return render_to_response('register.html', {
'form': form,
}, context_instance=RequestContext(request))
def get_profile(request):
username = CustomUser.username
return render_to_response(request, 'profile.html', {'username': username})
urls.py
urlpatterns = patterns ('',
url(r'register$', 'apps.accounts.views.register', name='register'),)
register.html
{% load staticfiles %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<body>
{% block body %}
<form method='POST' action="register" enctype= 'multipart/form-data'>{% csrf_token %}
<table>{{ form.ast_table}}</table>
<input type='submit' class="btn btn-default" value="Register" />
</form>
{% endblock %}
</body>
</html>
It seems that you don't have the right signature for the get_profile view function.
You should check your urls, you probably have something like
url(r'^profile/(?P<username>\w+/$', get_profile),
If so, your view should be
def get_profile(request, username):
#you can get the user
user = CustomUser.objects.get(username=username)
return render_to_response(request, 'profile.html', {'username': username, 'user': user})
CustomUser is the class. You need to fetch an instance before you can actually fetch its username.
Eg:
CustomUser.objects.get(pk=1).username
Gives you the username of the first user.
Also, its supposed to be {{form.as_table}} not ast_table