I am following a tutorial that has created the following registration form:
from django.contrib.auth.forms import UserCreationForm
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required = True)
class Meta:
model = User
fields = (
'username',
'first_name',
'last_name',
'email',
'password1',
'password2'
)
def save(self, commit = True):
user = super(RegistrationForm, self).save(commit= False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return User
Why isemail = forms.EmailField(required = True) the only field mentioned outside of class Meta, what is the purpose of this?
email field on the contrib.auth.AbstractUser (which is subclassed by User) has:
email = models.EmailField(_('email address'), blank=True)
which means that it is allowed to be blank.
Because we want it to be required in the form (for the purposes of the tutorial I assume), we must declare it explicitly.
If you want to create user registration system in django you can create forms.py file paste within it :
from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
class RegisterUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'input'}))
password2 = forms.CharField(label="Repeat password", widget=forms.PasswordInput(attrs={'class': 'input'}))
class Meta:
model = User
fields = ['username', 'email']
widgets = {
'username': forms.TextInput(attrs={'class': 'input'}),
'email': forms.EmailInput(attrs={'class': 'input'})
}
# Validating password
def clean_password2(self):
cd = self.cleaned_data
if cd['password2'] != cd['password']:
raise ValidationError("Password don't match")
return cd['password2']
And in views.py
-*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.http import HttpResponseForbidden, HttpResponse
from django.shortcuts import render
# Create your views here.
from django.views.generic import CreateView
from account.forms import RegisterUserForm
class RegisterUserView(CreateView):
form_class = RegisterUserForm
template_name = "account/register.html"
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated():
return HttpResponseForbidden()
return super(RegisterUserView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
user = form.save(commit=False)
user.set_password(form.cleaned_data['password'])
user.save()
return HttpResponse('User registered')
We override the dispath() method to make sure that the user can access the form if and only if he's not authenticated .
And for form_valid method we encrypt the password using set_password() method and then we commit to the database.
You probably will redirect the user if success rather than returning HttpResponse() as i did .
Because the default UserCreationForm doesn't have the EmailField which represents the email. But it has the other fields and there's no need to add them.
If you added a special field that is not included in the UserCreationForm like the EmailField you have to add it there.
Related
I want to login with email not username like this, please help
class loginUser(View):
def get(self, request):
lF = loginForm
return render(request, 'UserMember/login.html', {'lF': lF})
def post(self, request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return render(request, 'UserMember/private.html')
else:
return HttpResponse('login fail')
First thing is to create a default email field.
# models.py
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
# settings.py (remember to migrate)
AUTH_USER_MODEL = 'accounts.CustomUser' # new
Next, create your custom email backend:
# backends.py (in-app)
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserModel.objects.get(
Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
# settings.py (migrate again)
AUTH_USER_MODEL = 'accounts.CustomUser'
AUTHENTICATION_BACKENDS = ['accounts.backends.EmailBackend'] # new
If you plan on using Django's default register/login forms, do:
# form.py
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model
from django import forms
class RegisterForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = ('email', 'username', 'password1', 'password2')
class LoginForm(AuthenticationForm):
username = forms.CharField(label='Email / Username')
And then it's only the views and URLs to handle.
Ref
you need to work with allAuth
Follow this Link
hope it will be helpful.
Right now, if I enter invalid data into my UserCreationForm and submit it, the page reloads but doesn't show any error. I would like the EmailValidator validator in Django to show the error. I have tried adding the validators attribute to the email field, but it didn't do anything.
Here are my views:
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render
from django.urls import reverse
from .models import CustomUserCreationForm
# Create your views here.
def register(request):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse('index'))
elif request.method == 'GET':
form = CustomUserCreationForm()
elif request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
form.save()
context = {
'user': request.user,
}
return HttpResponseRedirect(reverse('index'), context)
else:
return HttpResponseRedirect(reverse('register'))
else:
return HttpResponse("Project 3: TODO")
context = {
'form': form,
}
return render(request, 'registration/signup.html', context)
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse('login'))
And here are my models:
from django.contrib.auth.models import AbstractUser, AbstractBaseUser
from django import forms
from django.contrib.auth.models import User
from django.db import models
from django.contrib.auth.forms import UserCreationForm
from django.core.validators import EmailValidator
# Create your models here.
# Customer class.
class CustomUser(User):
REQUIRED_FIELDS = ['email', 'first_name', 'last_name']
# Create user registration form class.
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(required=True, max_length=150, help_text='Required.')
last_name = forms.CharField(required=True, max_length=150, help_text='Required.')
email = forms.CharField(required=True, max_length=150, help_text='Required.', validators=[EmailValidator], error_messages={'invalid': 'This does not look like an email address.'})
class Meta:
model = User
fields = UserCreationForm.Meta.fields + ('first_name', 'last_name', 'email',)
# TODO: show an error message when email is incorrectly formatted.
# TODO: make email field unique and show an error message when it was already used.
Use built in EmailField of Django in CustomUserCreationForm
email = forms.EmailField(...)
See this too (validation of email) (form.clean), read this for showing errors of individual form fields
I know that this is a frequent topic, but however, with all the resources available on the web and stackoverflow, I couldn't get my form to work properly.
I get this error : Exception Type: RelatedObjectDoesNotExist, Exception Value:
User has no profile.
Here is my setup in Django.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if kwargs.get('created', False):
Profile.objects.create(user=kwargs['instance'])
post_save.connect(create_user_profile,sender=User)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, created,**kwargs):
if created:
instance.profile.save()
forms.py
from django.contrib.auth.models import User
from django import forms
from django.contrib.auth.forms import UserCreationForm
class SignUpForm(UserCreationForm):
birth_date = forms.DateField()
location = forms.CharField()
password1 = forms.CharField(label=("Password"), widget=forms.PasswordInput)
password2 = forms.CharField(label=("Confirm password"), widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'location','email', 'birth_date')
widgets = {
'birth_date': forms.DateInput(attrs={'class':'datepicker'}),
}
labels = {
'username': ('Capser name'),
}
help_texts = {
'username' : None,
'birth_date': None,
}
views.py
class UserFormView(View):
form_class = SignUpForm
template_name = 'home/registration_form.html'
#display a blank form
def get(self, request):
form = self.form_class(None)
return render (request, self.template_name, {'form': form})
#process form data
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
#user.refresh_from_db() # load the profile instance created by the signal
password = form.cleaned_data['password1']
user.set_password(password)
username = form.cleaned_data['username']
user.profile.birth_date = form.cleaned_data.get('birth_date')
user.profile.location = form.cleaned_data.get('location')
user.save()
#return user objects if credentials are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('home:home')
return render (request, self.template_name, {'form': form})
And if I uncomment the commented lins user.refresh_from_db(), i get the following error : Exception Type: DoesNotExist, Exception Value:
User matching query does not exist.
I'm not sure at all, but I suspect that the signals in the models.py are not working properly.
Anyone could help ?
First of all, you can't assign: user.profile, because user is an instance of the model User, which does not have this attribute.
I would not recommend this structure that you are using to create profile after creating a User using signals. You'd better create the User with its attributes (username, password, email) and then create the Profile instance.
user.save()
Profile.objects.create(
user=user,
location=form.cleaned_data.get('location'),
birth_date=form.cleaned_data.get('birth_date'))
If you still want to use signals to this task, you should search for "How to pass arguments by signals". So, you would pass location and birth_date by a dictionary and use this data to create a Profile.
I am trying to extend the User model to create a Profile model. The following code successfully displays a form with the additional fields I specified as location and bio. But when I submit the form only the original username, first_name, last_name, email, and password fields are stored in the database at http://127.0.0.1:8000/admin, none of my custom fields are stored in the Profile section I added to admin . I also get the following error:
IntegrityError at /accounts/register/
NOT NULL constraint failed: accounts_profile.user_id
Request Method: POST
Request URL: http://127.0.0.1:8000/accounts/register/
Django Version: 1.11.2
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: accounts_profile.user_id
Exception Location: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py in execute, line 328
Python Executable: /Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
forms.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required = True)
class Meta:
model = User #model User comes with username, email, first name, last name , pass1 and pass2 fields
fields = (
'username',
'email',
'first_name',
'last_name',
'password1',
'password2'
)
def save(self, commit = True):
user = super(RegistrationForm, self).save(commit = False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('location','bio')
views.py:
from django.shortcuts import render, redirect
from .forms import RegistrationForm,ProfileForm
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
profile_form = ProfileForm(request.POST)
if form.is_valid() and profile_form.is_valid():
form.save()
profile_form.save()
return redirect('login')
else:
form = RegistrationForm()
profile_form = ProfileForm()
return render(request, 'accounts/register.html', {'form': form, 'profile_form': profile_form})
urls.py:
from django.conf.urls import url
from django.contrib.auth.views import login
from . import views
urlpatterns = [
# /accounts/
url(r'^$', views.index, name = 'accounts'),
# /accounts/register/
url(r'^register/$', views.register, name='register'),
url(r'^login/$', login, {'template_name': 'accounts/login.html'}, name='login'),
]
admin.py:
from django.contrib import admin
from .models import Profile
# Register your models here.
admin.site.register(Profile)
# Register your models here.
Any help would be greatly appreciated.
you have to set the relation manually then your view should look like this:
if form.is_valid() and profile_form.is_valid():
user_object = form.save()
a = profile_form.save(commit=False)
a.user = user_object
a.save()
return redirect('login')
you can't do register and profile POST at a time.because your profile model is 1to1field it belongs to Userwhich means existing user can create one user profile.So initially user should create their registered account than only they can create profile.
I have created a custom User registration form, from the UserCreationForm. When I try to register, it does register successfully, and I can see a newly created user with the username and its email. But there's no password for that user.
In the admin, the password field for that user is No password set.. Please correct me where I am wrong. Thank you.
forms.py:
from album.forms import MyRegistrationForm
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2',)
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
views.py:
def register_user(request):
if request.method == "POST":
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success/')
else:
form = MyRegistrationForm()
return render(request, 'register.html', {'form':form})
When calling save on the superclass using super, use the form MyRegistrationForm, not its superclass UserCreationForm.
user = super(MyRegistrationForm, self).save(commit=False)