Django save user and profile with signals - python

Im still learning Django and I am stuck at user registration / profile creation.
My goal
So, the purpose of this is to save the new user and at the same time save the profile of the new user with de data from the form. I use 2 forms u_form and p_form.
What I have done so far:
Created model Profile with OneToOneField to User
Created 2 forms for User (u_form) and Profile (p_form)
Created signals.py to create new Profile when new User is created
In the view I have create function with u_form.save()
Problem
This works, but the new Profile is completely empty.. When I put p_form.save() in my view it gives me this error:
NOT NULL constraint failed
The code
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)
voorletter = models.CharField(max_length=10)
voorvoegsel = models.CharField(max_length=10)
achternaam = models.CharField(max_length=200)
depers = models.CharField(max_length=25)
depersoud = models.CharField(max_length=25)
telefoonnummer = models.CharField(max_length=25)
class Meta:
verbose_name = "Collega"
verbose_name_plural = "Collega's"
def __str__(self):
return self.depers
signals.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
views.py
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from gebruikers.forms import UserRegisterForm, ProfileRegisterForm
def gebruiker_create(request):
if request.method == "POST":
u_form = UserRegisterForm(request.POST)
p_form = ProfileRegisterForm(request.POST)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
messages.success(request, f'Account is aangemaakt.')
return redirect('login')
else:
u_form = UserRegisterForm()
p_form = ProfileRegisterForm()
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'users/register.html', context)
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Profile
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(label = "Email")
password1 = forms.CharField(widget=forms.TextInput(attrs={'type':'password'}), label="Wachtwoord", help_text=None)
password2 = forms.CharField(widget=forms.TextInput(attrs={'type':'password'}), label="Wachtwoord herhalen", help_text=None)
class Meta:
model = User
fields= ['username', 'email', 'password1', 'password2']
class ProfileRegisterForm(forms.ModelForm):
voorletters = forms.CharField(label="Voorletters", max_length=10)
voorvoegsel = forms.CharField(label="Voorvoegsel", max_length=50)
achternaam = forms.CharField(label='Achternaam', max_length=100)
depers = forms.CharField(label='Depers', max_length=8)
depersoud = forms.CharField(label='Oude Depers', max_length=50)
telnummer = forms.CharField(label="Telefoonnummer", max_length=20)
class Meta:
model = Profile
fields = ['voorletters', 'voorvoegsel', 'achternaam', 'depers', 'depersoud', 'telnummer']

If you want Profile fields to be empty initially just add blank=True in every model fields except for user .
voorletter = models.CharField(max_length=10, blank=True)
.....
.....
.....
telefoonnummer = models.CharField(max_length=25, blank=True)
Then run makemigrations and migrate command to successfully make the changes in the database.
it will solve NOT NULL constraint failed error

Related

Django - Edit User Form and Profile Form To change Information and User Profile Picture

So In my Django Admin I have a User section (that comes default) and I made a profile section in my forms.py file. I want to add an option when you click in the profile page to redirect to and 'edit' profile page where a user can change their user/profile info including their picture. I'm still pretty knew to Django so I don't know where I need to begin. I have snippets of my code from different parts of my Django app to show because currently I don't know where to start.
Models.py File:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
# User Profile Model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False, blank=True)
profile_pic = models.ImageField(default='static/chat/images/default-profile-photo.jpg', null=True, blank=True, upload_to='images/profile/')
def __str__(self):
return self.user.username
# Create Profile When New User Signs Up
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance)
user_profile.save()
post_save.connect(create_profile, sender=User)
fourms.py file:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
class SignUpForm(UserCreationForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
first_name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2')
def __init__(self, *args, **kwargs):
super(SignUpForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['password1'].widget.attrs['class'] = 'form-control'
self.fields['password2'].widget.attrs['class'] = 'form-control'
Views.py file:
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib import messages
from chat.forms import SignUpForm
# Create your views here.
def chatPage(request, *args, **kwargs):
if not request.user.is_authenticated:
return redirect('login-user')
context = {}
return render(request, 'chat/chatPage.html', context)
def test(request):
return render(request, 'chat/test-chat.html')
def register_user(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
messages.success(request, ('Registration Successful!'))
return redirect('chat-page')
else:
form = SignUpForm()
return render(request, 'chat/register_user.html', {'form': form})
def profilePage(request):
return render(request, 'chat/profilePage.html')
def EditProfilePage(request):
return render(request, 'chat/editProfile.html')
My current editprofile.html page is blank at the moment because I know I need to start in other files before working on the html page.

UNIQUE constraint failed: new__users_profile.user_id. Python Django

django.db.utils.IntegrityError UNIQUE constraint failed
sqlite3.IntegrityError: UNIQUE constraint failed: new__users_profile.user_id
The above exception was the direct cause of the following exception:
new__users_profile.user_id
Error occurs when I'm trying to register new user, login to an existing user and when I am trying to migrate. I've tried to delete all migrations and migrate once again but it didn't help
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
class Media(models.Model):
image_name = models.CharField(max_length=50)
image_description = models.CharField(max_length=80)
image_image = models.ImageField(upload_to='media', default='default.jpg')
views
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from .forms import UserRegisterForm, MediaForm
from .models import Media
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
#login_required
def profile(request):
if request.method == 'GET':
media_images = Media.objects.all()
context = {
'media_images':media_images,
}
return render(request, 'users/profile.html', context)
#login_required
def add_media(request):
if request.method == 'POST':
form = MediaForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('http://127.0.0.1:8000/')
else:
form = MediaForm()
return render(request, 'users/add_media.html', {'form':form})
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import *
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class MediaForm(forms.ModelForm):
class Meta:
model = Media
fields = ['image_name', 'image_description', 'image_image']
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
I think you need primary_key=True,
class Profile(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE, null=True)
In class profile, add primary_key=True and remove null=True
user = models.OneToOneField(User,primary_key=True, on_delete=models.CASCADE)
I hope it will work!

How to add extra fields to registration end point of rest-auth

I am using rest-auth registration api for user registration. I have some extra fields in the UserProfile model.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
org_id = models.CharField(max_length=100, default='')
is_teacher = models.BooleanField(blank=True, default=False)
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
The UserProfile model is shown above. How can I add these fields to rest-auth regestration api endpoint and save the data to database.
I found an answer for myself
The serializers can be written as
from rest_framework import serializers
from rest_auth.registration.serializers import RegisterSerializer
from .models import UserProfile
class RegistrationSerializer(RegisterSerializer):
first_name = serializers.CharField(required=False)
last_name = serializers.CharField(required=False)
personal_id = serializers.CharField(required=True)
def custom_signup(self, request, user):
user.first_name = self.validated_data.get('first_name', '')
user.last_name = self.validated_data.get('last_name', '')
user.userprofile.personal_id = self.validated_data.get(
'personal_id', '')
user.save(update_fields=['first_name', 'last_name'])
user.userprofile.save(update_fields=['org_id'])
I didnt add the is_teacher because its optional.
In views.py extend the RegisterView of the rest_auth.regeistration.views to pass this data and its done.
class RegistrationView(RegisterView):
serializer_class = RegistrationSerializer
And finally add a url and pass RegisterView.as_view().

Extending the Django User Model OneToOne - User profile not saving

I am trying to build an application that allows users to register and meet other users with similar interests. I am extending the user model using a OneToOne field but I run into a problem when I try to register some users: The profile does not save. The user data saves, but the profile data does not.
I do not understand what I am doing wrong, as I followed a tutorial to write the program.
This is my Models.py file:
class Profile(models.Model):
GENDERS = (
('M', 'Male'),
('F', 'Female'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
email = models.EmailField(max_length=254, blank=True)
gender = models.CharField(choices=GENDERS, max_length=1, null=True, default='')
dob = models.DateField(auto_now=False, auto_now_add=False, blank=True, null=True)
hobby = models.ManyToManyField(Hobby)
def __str__(self):
return self.user.username
#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()
post_save.connect(create_user_profile, sender=User)
This is my forms.py file:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'password', 'first_name', 'last_name')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('email', 'gender', 'dob', 'hobby')
This is my view function:
def register(request):
if request.method =="POST":
userForm = UserForm(request.POST)
profileForm = ProfileForm(request.POST)
if userForm.is_valid() and profileForm.is_valid():
userForm.save()
profileForm.save()
return redirect('/')
else:
return render(request, 'QMLove/register.html', {'userForm': userForm, 'profileForm': profileForm})
else:
userForm = UserForm()
profileForm = ProfileForm()
return render(request, 'QMLove/register.html',{'userForm': userForm, 'profileForm': profileForm})
Thank you in advance!
You haven't done anything to associate the Profile you're creating with the User you've created. I would expect either two profiles two be created - one empty and one with data but not associated with the user - or for the profile form save to fail with an integrityerror because you didn't supply the user.
You should remove those signal receivers because they won't help with what you want to do and will probably create conflicts. Instead, pass the created user when you save the profile:
user = userForm.save()
profile = profileForm.save(commit=False)
profile.user = user
profile.save()

models.py and views.py may be conflicting

Below are the output of the models.py
from django.db import models
from django.core.urlresolvers import reverse
#from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Registration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length = 250)
password = models.CharField(max_length = 250)
email = models.CharField(max_length = 250)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Registration.objects.create(username=instance)
instance.registration.save()
Below is the output of the views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import UserCreationForm
from .forms import SignUpForm
from django.views import generic
class IndexView(generic.View):
templet_name = 'user_info/index.html'
def signupview(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('registration_form.html')
else:
form = SignUpForm()
return render(request,'user_info/registration_form.html', {'form': form})
I have two questions:
1) In my models.py I have 4 fields, 'user','username','password','email'. In my first field "user", I guess, I shouldn't be using "models.OneToOneField(User, on_delete=models.CASCADE)", because, as per my understanding, it's used when we have a primary key and foreign key in working. Please correct me if I am wrong.
2) in my views.py, the function "signupview", I am saving the form in the database through form.save(), and then cleaned the data. have I done the right thing, as my models.py has 4 fields, but in view.py , I am giving only two fields
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password')
I hope I am making sense here. I am getting an error while creating a superuser through
python manage.py createsupseruser
Below is the error
django.db.utils.IntegrityError: NOT NULL constraint failed: user_info_registration.user_id
That is why I am asking these questions.
forms.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
#from django.forms import ModelForm
class SignUpForm(UserCreationForm):
#first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
#last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = User
fields = ('username','password1','email')
Latest look of models.py:
from django.db import models
from django.contrib.auth.models import User
class Registration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
The reason you get the error is that the User post save signal tries to create a Registration instance, but you don't supply values for all the required fields.
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Registration.objects.create(username=instance)
instance.registration.save()
You either have to remove this signal handler or you have to provide valid arguments to Registration.objects.create().

Categories

Resources