Saving a extended user profile - django

I need save additional information about users when they register.
I used this:
https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
, but I stuck. Relation are created, but the field key is empty.
models.py
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, unique=True)
key = models.CharField(max_length=20, null=True, blank=True)
def __unicode__(self):
return u'%s' % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
views.py
def registration(request):
form = RegistrationForm(request.POST or None)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user = User.objects.create_user(login, email, password)
user.first_name = first_name
user.last_name = last_name
user.is_active = False
# I've tried both ways, but it not write anything in to the table
# user.key = ''.join(random.choice(string.digits) for i in range(12))
# user.get_profile().key = ''.join(random.choice(string.digits) for i in range(12))
user.save()
Thanks.

profile = user.get_profile()
profile.key = ''.join(random.choice(string.digits) for i in range(12))
profile.save()
user.save()
This is the correct way to do it. You have to save the instance of the profile object as well as the user object

You can also try this,
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()

Related

How can i save custom fields in registration from to my database? (Django)

I'm trying to create a school related website with django. So i created a custom user model looks like this (Sorry for the foreign field names):
class ogrenciler(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
ogr_adi = models.CharField(max_length=30)
ogr_soyadi = models.CharField(max_length=30)
sinifi = models.ForeignKey(siniflar, null=True, on_delete=models.CASCADE)
numara = models.CharField(max_length=5)
foto = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return self.ogr_adi + " " + self.ogr_soyadi + "ogrencisi"
and this is my custom registiration form:
class ogrenciKayit(UserCreationForm):
email = forms.EmailField()
numara = forms.CharField(max_length=5, required=True)
class Meta:
model = User
fields = ['username', 'email', 'numara', 'password1', 'password2']
def save(self, commit=True):
user = super(ogrenciKayit, self).save(commit=False)
user.numara = self.cleaned_data['numara']
if commit:
user.save()
return user
I created a signal.py file to whenever a user created also create a "ogrenci"(student). This is my signals.py file:
#receiver(post_save, sender=User)
def create_ogrenci(sender, instance, created, **kwargs):
if created:
ogrenciler.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_ogrenci(sender, instance, **kwargs):
instance.ogrenciler.save()
Everything works fine but the "numara" field doesn't get saved.
This is my views.py file if you wanna check it:
def ogrenciregister(request):
if request.method == 'POST':
form = ogrenciKayit(request.POST)
if form.is_valid():
form.save()
username= form.cleaned_data.get('username')
messages.success(request, f'Hesap {username} adına oluşturuldu.')
return redirect('giris')
else:
form = ogrenciKayit()
return render(request, 'kullanicilar/ogrencikayit.html', {'form': form})
First, explain why the field can not be saved.
#receiver(post_save, sender=User)
The sender is just the user in the database, It is not the object you returned in your save function. It don not have the field you want
write the creation of related object in your save function of form .
In this way you can get the value of field

Django post_save() signal to register new user

Below is the createprofileview class-based view to register a new user and also to create the profile of that user at the same time.
class CreateProfileView(CreateView):
model = Profile
def post(self, request):
user_form = UserForm(request.POST)
profile_form = ProfileForm(request.POST, request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
return HttpResponseRedirect(reverse('home', args=[]))
messages.warning(request, 'Something went wrong in Venter, please try again')
def get(self, request):
user_form = UserForm()
profile_form = ProfileForm()
return render(request, './mysite/registration.html', {'user_form': user_form, 'profile_form': profile_form})
I have used post_save() signal along with my Profile model as follows:
class Profile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key = True
)
organisation_name = models.ForeignKey(
Organisation,
on_delete= models.CASCADE,
null=True,
)
profile_picture = models.ImageField(
upload_to='Organisation/Employee Profile Picture/%Y/%m/%d/',
null=True,
blank=True,
)
phone_number = models.CharField(
blank=True,
max_length=10
)
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()
However, the user gets created and saved, but its profile details do not get saved.
I am unsure how to tweak the signals function suitable to my requirements of registering a new user and also creating their profile at the same time.
Here is the forms.py:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'password', 'email', 'first_name', 'last_name')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('organisation_name', 'phone_number', 'profile_picture')
I don't see the point of having a profile creation signal, because you are already having a ProfileForm to get the Profile Data. I think you can get rid of the profile signals and update the view to save the profile form directly. Like this:
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
# rest of the code
Update
from comments
You need to set your password in User object. You can do that in your form's save method by overriding like this(using set_password method):
class UserForm(...):
...
def save(self, **kwargs):
user = super(UserForm, self).save(commit=False)
password = self.cleaned_data.get('password')
user.set_password(password)
user.save()
return user

post profile information in django extended user model (user has no profile)

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.

Issue with extending django model

I have a site where you can sign up to be either someone who uses the service(customer) or someone who provides the service(worker). I have created two profiles in models.py to represent each. They are both extremely similar for the most part as of right now. Both forms display properly when you go to them, and if you are signing up as a customer and press submit everything goes smoothly and a new user under will show up in "Customer profiles" at http://127.0.0.1:8000/admin/ . But if you try to sign up as a worker, the following error appears:
Exception Type: RelatedObjectDoesNotExist
Exception Value:
User has no workerprofile.
I do not understand this because as you will see in the code below i use customerprofile and it works fine, if I use workerprofile it crashes.
Views.py:
def signup_as_worker(request):
if request.method == 'POST':
form = WorkerSignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.workerprofile.birth_date = form.cleaned_data.get('birth_date')
user.workerprofile.university = form.cleaned_data.get('university')
user.save() # explicitly save custom fields not in User model
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user) # login user after signup
return redirect('home')
else:
form = WorkerSignUpForm()
return render(request, 'core/signup_as_worker.html', {'form': form})
def signup_as_customer(request):
if request.method == 'POST':
form = CustomerSignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.customerprofile.birth_date = form.cleaned_data.get('birth_date')
user.customerprofile.university = form.cleaned_data.get('university')
user.save() # explicitly save custom fields not in User model
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user) # login user after signup
return redirect('home')
else:
form = CustomerSignUpForm()
return render(request, 'core/signup_as_customer.html', {'form': form})
forms.py:
class WorkerSignUpForm(UserCreationForm):
#birth_date and university fields need to be declared seperately because they are not apart of User:
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
university = forms.CharField()
class Meta:
model = User
fields = ('username',
'email',
'first_name',
'last_name',
'birth_date',
'university',
'password1',
'password2', )
class CustomerSignUpForm(UserCreationForm):
#birth_date and university fields need to be declared seperately because they are not apart of User:
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
university = forms.CharField()
class Meta:
model = User
fields = ('username',
'email',
'first_name',
'last_name',
'birth_date',
'university',
'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 WorkerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
university = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
role = models.CharField(max_length = 10, default = 'USER')
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_worker_profile(sender, instance, created, **kwargs):
if created:
WorkerProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_worker_profile(sender, instance, **kwargs):
instance.workerprofile.save()
class CustomerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
university = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
role = models.CharField(max_length = 10, default = 'CUSTOMER')
needLaundryDone = models.BooleanField(default = False)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_worker_profile(sender, instance, created, **kwargs):
if created:
CustomerProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_worker_profile(sender, instance, **kwargs):
instance.customerprofile.save()
I do not understand what the problem is.
Your signal handler method names for both models are the same. You are practically redefining the methods therefore only the second set of methods are called. Rename your CustomerProfile handlers to create_customer_profile and save_customer_profile.

Django: Extended User Model Cant Save

I have extended the django user model with another model called profile:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
chosenCharity = models.ForeignKey('meta.Charity', db_column='chosenCharityid', related_name='user_chosenCharity')
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()
When I try to create a new user within the view with the code below i get the following error "(1048, "Column 'chosenCharityid' cannot be null")":
#transaction.atomic
def register(request):
selectedTeams = StraightredTeam.objects.filter(Q(teamid=request.session['team1id']) | Q(teamid=request.session['team2id'])).order_by('teamname')
request.POST.get('currentCharities')
next_url = request.POST.get('next', request.GET.get('next', reverse('straightred.payment')))
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
new_user = form.save()
I know when a user has already created I should be able to use:
user = User.objects.get(pk=user_id)
user.profile.chosenCharity = 12
user.save()
But I am unsure how to do this when creating the user. Any help would be appreciated.
Below is a copy of the registration form to help:
class RegistrationForm(BootstrapModelForm, UserCreationForm):
email_opt_in = forms.BooleanField(label='Receive DWAD e-mail updates', required=False)
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
# The default Django user model doesn't require these fields to be set
# but we do.
self.fields['email'].required = True
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email__iexact=email).exists():
raise ValidationError('There is already an account registered with this e-mail address.')
return email
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'username']
Charity Model:
class Charity(models.Model):
name = models.CharField(max_length=50, unique=True)
website = models.URLField()
enabled = models.BooleanField(default=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
verbose_name_plural = 'charities'
don't create the Profile object in post_save signal. You cannot access the required charity id in create_user_profile method. So remove that part of code.
instead save the profile object right after you save your user object in your register view like this:
#transaction.atomic
def register(request):
selectedTeams = StraightredTeam.objects.filter(Q(teamid=request.session['team1id']) | Q(teamid=request.session['team2id'])).order_by('teamname')
request.POST.get('currentCharities')
next_url = request.POST.get('next', request.GET.get('next', reverse('straightred.payment')))
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
new_user = form.save()
charity_id = request.session['chosenCharityid']
# create profile object
Profile.objects.create(user=new_user, chosenCharity_id=charity_id)
EDIT:
I see that you are using another method save_user_profile to receive the post_save signal.
Don't use this either. It a round about way of doing a simple straight forward thing.
Using you own code sample:
user = User.objects.get(pk=user_id)
# here you are assigning a new charity id to the profile object
user.profile.chosenCharity = 12
# you save the user object on which nothing has changed
# instead you should save the profile object
user.save() # no need
user.profile.save() # direct and logical