I have written an extension of the Django auth.user model which adds middle_name and phone fields to the model.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
middle_name = models.CharField(max_length=20, blank=True)
phone = models.CharField(max_length=10, blank=True)
def __str__(self):
return(f'{self.user.username} profile')
I am using the following forms to accept input from the user.
class RegistrationForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'username', 'password1', 'password2']
class ProfileForm(forms.ModelForm):
phone = forms.CharField(max_length=10, min_length=10)
middle_name = forms.CharField(max_length=20, required=True)
class Meta:
model = Profile
fields = ['middle_name', 'phone']
The view for the register route is as follows:
def register(request):
if request.method == 'POST':
user_form = RegistrationForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
username = user_form.cleaned_data.get('username')
user_form.save()
profile_form.save()
messages.success(request, f'Welcome { username }! Your account has been created. Sign in to continue.')
return redirect('login')
else:
return render(request, 'home/register.html', { 'user_form': user_form, 'profile_form': profile_form })
else:
user_form = RegistrationForm()
profile_form = ProfileForm()
return render(request, 'home/register.html', { 'user_form': user_form, 'profile_form': profile_form })
This is contents of the signals.py file
from django.contrib.auth.models import User
from django.db.models.signals import post_save
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()
The issue is while a row for the user is getting created in the Profile model, data is not getting written into the fields of the row. I am seeing a Exception Value: NOT NULL constraint failed: home_profile.user_id
By using a signal, you will create a Profile object, but the profile_form will be unaware of that, and thus create another one that does not link to the user. You thus might want to remove the signals. Signals are often an anti-pattern, and furthermore there are several ORM calls that can circumvent the signals.
If you remove the signals, you will still need to link the Profile object wrapped in your profile_form to the user, you do this with:
# remove the signal that constructs a Profile
def register(request):
if request.method == 'POST':
user_form = RegistrationForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save() # ← assign the user to a variable
profile_form.instance.user = user # ← set it as user of the profile
profile_form.save()
messages.success(request, f'Welcome {user.username}! Your account has been created. Sign in to continue.')
return redirect('login')
else:
user_form = RegistrationForm()
profile_form = ProfileForm()
return render(request, 'home/register.html', { 'user_form': user_form, 'profile_form': profile_form })
Related
views.py
def register_view(request):
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
user = form.save()
## login(request,user)
messages.success(request,'Account created succcessfully')
return redirect('login')
else:
messages.error(request,'Invalid information! Please retry!')
else:
form = UserForm()
context = {'form':form}
return render(request,'register.html',context)
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username,password=password)
if user is not None:
login(request,user)
return redirect('homepage')
else:
messages.error(request,'No current user!')
else:
form = AuthenticationForm()
context = {'form':form}
return render(request,'login.html',context)
def logout_view(request):
logout(request)
return redirect('login')
#login_required
def profile(request):
Profile.objects.get_or_create(user=request.user)
if request.method == 'POST':
u_form = UserUpdateForm(request.POST,instance=request.user)
p_form = ProfileForm(request.POST,request.FILES,instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request,'Profile updated successfully!')
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileForm(instance=request.user.profile)
context = {
## 'user':request.user,
'u_form':u_form,
'p_form':p_form,
}
return render(request,'profile.html',context)
signals.py
#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()
models.py
class Profile(models.Model):
name = models.OneToOneField(User,on_delete=models.CASCADE)
mobile = models.IntegerField(null=True)
address = models.CharField(max_length=350,null=True)
image = models.ImageField(upload_to='profile_pics', default='default.png',null=True)
def __str__(self):
return str(self.name.username)+'\'s Profile'
forms.py
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['mobile', 'address', 'image']
Error msg:
RelatedObjectDoesNotExist at /login/
User has no profile.
I am facing an issue that the user profile could not get created or updated although I used the signals for the profile model. When I login a registered user, the error message told me that User has no profile. However if I login a user that has created a profile it could show the related information so for newly registered user how to automatically create a profile for that user?
because you have a existing which does not have any profile because didn't load signal then wile creating that user if it is superuser create the new superuser from terminal delete the existing one who doesn't have profile after login in admin panel by the way i am also using signal for my web here is the code how i use it
my models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
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,)
profile_pic = models.ImageField(upload_to='profile_pics', default='default.png',)
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=75, blank=True)
dob = models.DateField(blank=True, null=True)
joined_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, *args, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
tell me if you still got error
I used extend user model based on this tutorial.When I submit the registration form this error occurs.This errors shows for both time I use is_active() and is_active in my code.
How to resolve this error?
Error
registration form
new error
Here is my 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)
full_name = models.CharField(max_length=256, blank=False)
codeforces_id = models.CharField(max_length=256, blank=False)
Uva_Id = models.CharField(max_length=256, blank=False)
#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.http import HttpResponse
from django.shortcuts import render,redirect
from django.contrib.auth import authenticate,login
from django.views import generic
from django.views.generic import View
from .forms import UserForm,ProfileForm
class UserFormView(View):
user_form_class = UserForm
profile_form_class= ProfileForm
#display a blank form
def get(self , request):
user_form = self.user_form_class(None)
profile_form = self.profile_form_class(None)
return render(request, 'website/registration_form.html',{
'user_form':user_form,
'profile_form':profile_form
})
#process form data
def post(self, request):
user_form = self.user_form_class(request.POST)
profile_form = self.profile_form_class(request.POST)
user= user_form.save(commit= False)
if user_form.is_valid() and profile_form.is_valid():
password= user_form.cleaned_data['password']
username = user_form.cleaned_data['username']
user.set_password(password)
user_form.save()
profile_form.save()
# auto login
user = authenticate(username =username, password = password)
if user is not None:
if user.is_active():
login(request,user)
return redirect('website:index')
return render(request, 'website/registration_form.html',{
'user_form':user_form,
'profile_form':profile_form
})
You saved the form before validate.
Add user = user_form.save(commit= False) into your if statement
def post(self, request):
user_form = UserForm(request.POST, instance=request.user)
profile_form = ProfileForm(request.POST, instance=request.user.profile)
if user_form.is_valid() and profile_form.is_valid():
user= user_form.save(commit= False)
password= user_form.cleaned_data['password']
username = user_form.cleaned_data['username']
user.set_password(password)
user.save() # You can update user object like this
profile_form.save()
# auto login
user = authenticate(username =username, password = password)
if user is not None:
if user.is_active():
login(request,user)
return redirect('website:index')
return render(request, 'website/registration_form.html',{
'user_form':user_form,
'profile_form':profile_form
})
The second error caused because when call user.save() it automatically executes the signal defined in your model. But you commented #receiver(post_save, sender=User). It is crucial and uncomment it.
I'm using two ModelForms to create na user with a Profile instance. Profile ModelForm has a single field. I'm doing form.save(commit=False), setting the required field (country) other than the one in the form and saving. I get an error saying that 'country_id' cannot be null.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
email_confirmed = models.BooleanField(default=False)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
forms.py
class UserRegisterForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class ProfileRegisterForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['country']
views.py
def register(request):
if request.method == 'POST':
user_form = UserRegisterForm(request.POST)
profile_form = ProfileRegisterForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save(commit=False)
user.is_active = False
profile = profile_form.save(commit=False)
profile.user = user
user.save()
current_site = get_current_site(request)
subject = 'Activate Your Account'
message = render_to_string('account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': account_activation_token.make_token(user)
})
user.email_user(subject, message)
return redirect('activation_email_sent')
else:
user_form = UserRegisterForm()
profile_form = ProfileRegisterForm()
return render(request, 'register.html', {'user_form': user_form, 'profile_form': profile_form})
Yeah. I removed the post_save, made country nullable and saved user and profile separately. Thanks for the help.
views.py
def register(request):
if request.method == 'POST':
user_form = UserRegisterForm(request.POST)
profile_form = ProfileRegisterForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save(commit=False)
user.is_active = False
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
I need to create admin panel in django , admin will be able to add students"which extended from users " , I finally be able to add them , but after that I get "'AnonymousUser' object has no attribute '_meta'
User is added to the database correctly , But django logged me out !
How Can I keep my current user session !
class student(models.Model):
Computers = 1
Communications = 2
Dep_CHOICES = (
(Computers, 'Computers'),
(Communications, 'Communications'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
dep = models.PositiveSmallIntegerField(choices=Dep_CHOICES, null=True, blank=True)
deg = models.FloatField(null=True, blank=True)
def __str__(self): # __unicode__ for Python 2
return self.user.username
def create_user_profile(sender, instance, created):
if created:
student.objects.create(user=instance)
def save_user_profile(sender, instance , **kwargs):
instance.student.save()
class UserForm(ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'password')
class studentForm(ModelForm):
class Meta:
model = student
fields = ('dep', 'deg')
The view
def add_stu(request):
if request.method == 'GET':
return render(request, "add_student.html")
else:
user_form = UserForm(request.POST, instance=request.user)
profile_form = studentForm(request.POST, instance=request.user.student)
user_form.save()
profile_form.save()
you can't save profile_form directly as it has a foreign key relation to user and is required. so before you can save profile_form you need to save user and then add the user to profile.
def add_stu(request):
if request.method == 'GET':
return render(request, "add_student.html")
else:
user_form = UserForm(request.POST)
profile_form = studentForm(request.POST)
new_user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = new_user
profile.save()
I am trying to create an "edit profile" page/form and have followed the SimpleIsBetterThanComplex tutorial on how to extend the user model by way of the OneToOne Link. However, when i try to display the user profile form to allow the user to update their profile, the form doesn't display at all except for the Submit button... Any ideas where i might have gone wrong here?
models.py
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
from django.utils import timezone
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
#account types
is_userA = models.BooleanField('User A', default=True)
is_userB = models.BooleanField('User B', default=False)
is_superuser = models.BooleanField('SuperUser', default=False)
#other fields here
avatar = models.ImageField('avatar', upload_to='static/media/images/avatars/', null=True, blank=True)
phone = models.CharField('phone number', max_length=20, blank=True, default='')
address = models.CharField('address', max_length=100, default='', blank=True)
city = models.CharField('city', max_length=100, default='', blank=True)
state = models.CharField('state', max_length=2, default='', blank=True)
country = models.CharField('country', max_length=100, default='', blank=True)
date_joined = models.DateTimeField(default=timezone.now)
#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
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
views.py
#login_required
#transaction.atomic
def update_profile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
if user_form.is_valid():
user_form.save()
messages.success(request, _('Your profile was successfully updated!'))
return redirect('settings:profile')
else:
messages.error(request, _('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
return render(request, 'profiles/profile.html', {
'user_form': user_form,
})
template
<div class="col-md-12">
<div class="mb32">
<h5 class="uppercase">General Information</h5>
</div>
<div class="row">
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
<button type="submit">Save changes</button>
</form>
Your view looks for now looks like this:
views.py
#login_required
#transaction.atomic
def update_profile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
if user_form.is_valid():
user_form.save()
messages.success(request, _('Your profile was successfully updated!'))
return redirect('settings:profile')
else:
messages.error(request, _('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
return render(request, 'profiles/profile.html', {
'user_form': user_form,
})
According to this view if method POST, you validate enterd data from the form, but when its GET method you just define UserForm, so i think you have to make indent in the last line:
views.py
#login_required
#transaction.atomic
def update_profile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
if user_form.is_valid():
user_form.save()
messages.success(request, _('Your profile was successfully updated!'))
return redirect('settings:profile')
else:
messages.error(request, _('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
return render(request, 'profiles/profile.html', {
'user_form': user_form,
})
So your last line return render(request, 'profiles/profile.html', {'user_form': user_form,}) have to be under else statement, cause its GET as I understand.