Extending User Model Django, IntegrityError - django

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.

Related

How to validate the email field of UserCreationForm using the built-in EmailValidator in Django?

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

How to setup registration and signals in django 2.0

Can someone help me figure out what i am doing wrong trying to setup authentication and signals to work along with the models created in django 2.0.
models.py
from django.db import models
from django.conf import settings.AUTH_USER_MODEL
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
bio = models.TextField(foo)
location = models.CharField(foo)
# Override save method
# Run after the method is saved to add signal functionality below
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
else:
instance.profile.save()
forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.forms import ModelForm
from .models import Profile
Profile = get_user_model()
class UserRegisterForm(forms.ModelForm):
email = forms.EmailField(foo)
first_name = forms.CharField(foo)
last_name = forms.CharField(foo)
password = forms.CharField(foo)
password2 = forms.CharField(foo)
class Meta:
model = Profile
fields = [
'username',
'first_name',
'last_name',
'email',
'password1',
'password2'
]
views.py
from django.shortcuts import render, redirect
from django.contrib.auth import get_user_model
from .forms import UserRegisterForm
from .models import Profile
from django.conf import settings
def register(request):
next = request.GET.get('next')
form = UserRegisterForm(request.POST or None)
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get('password')
user.set_password(password)
user.save()
new_user = authenticate(username=user.username, password=password)
login(request, new_user)
if next:
return redirect(next)
return redirect('accounts:login')
context = {
'form': form,
}
return render(request, "accounts/register.html", context)
Foo = just a placeholder
The code above create the user but not the profile associated to it.
Any help would be much appreciated.

Extending User model in Django

I am trying to create a profile model for all of my users. I have the following code in which I get one custom field birth_date, but cannot seem to get any of my other custom fields to work:
forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
class Meta:
model = User
fields = ('username', 'first_name','last_name', 'birth_date','location', 'password1', 'password2', )
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()
views.py
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import SignUpForm
def home(request):
return HttpResponse('fd')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.birth_date = form.cleaned_data.get('birth_date')
user.profile.college = form.cleaned_data.get('college')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'accounts/profile.html', {'form': form})
urls.py
urlpatterns = [
url(r'^register/$', views.signup, name='profile'),
url(r'^home/$', views.home, name='home'),
]
If I were to remove locationfrom forms.py, the form would load properly and allow me to fill it out and upon submission all data, including the custom field birth_date would save. But when I try to add location to the form, I get the following error:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/forms/models.py", line 262, in __new__
raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (location) specified for User
I am not sure why I cannot add the location field to the form.
Because it's not a field on User. You need to do the same as you have for birth_date - declare it separately in the form class, and save it explicitly to the profile in the view.

Registration form django that inherits form UserCreationForm

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.

NOT NULL constraint failed: core_profile.user_id

I have a model named Profile which is created to extend the User auth model. I have created two forms one is UserForm and ProfileForm. In register.html template I show this two forms and wish to save in the database through the user.
But it constantly shows the exception: Integrity Error
NOT NULL constraint failed: core_profile.user_id
whenever I try to submit the post filling out all the fields and hit submit button.
Here are my models:
from __future__ import unicode_literals
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 update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
And here is my view for posting the forms:
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from .forms import SignUpForm, ProfileForm
#login_required
def home(request):
return render(request, 'home.html')
def signup(request):
if request.method == 'POST':
user_form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid():
user = user_form.save()
profile_form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.birth_date = user_form.cleaned_data.get('birth_date')
user.save()
raw_password = user_form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
user_form = SignUpForm()
profile_form = ProfileForm()
return render(request, 'signup.html', {'user_form': user_form, 'profile_form': profile_form})
And here are the forms:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Profile
class SignUpForm(UserCreationForm):
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'birth_date')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('bio', 'location')
Thank you,
When you are trying to save the profile_form, it doesn't know to which user it is related to. And in your case, when you save the user form, it will create the profile, and what you need to do is just update the profile of you saved user, so I suggest something like:
def signup(request):
if request.method == 'POST':
user_form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid():
user = user_form.save()
user.profile.bio = profile_form.cleaned_data.get('bio')
user.profile.location = profile_form.cleaned_data.get('location')
user.profile.save()
...
In addition to #Gagik Sukiasyan's answer: I added some additional things to reduce errors / ease your life:
transaction.atomic -> if errors occur, the database is being rolled back
and profile_form.is_valid() makes sure profile_form is validated
instead of going through the profile attributes manually I added a loop
Modified Code:
from django.db import transaction
#transaction.atomic
def register(request):
""" register a new user view """
if request.method == 'POST':
user_form = UserRegisterForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
for field in profile_form.changed_data:
setattr(user.profile, field, profile_form.cleaned_data.get(field))
user.profile.save()