Adding field to Profile when creating User - django

I have a signup form that looks like this:
class SignUpForm(UserForm):
username = forms.CharField(max_length=32, min_length=1)
initials = forms.CharField(max_length=3)
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())'
...
I'm creating the user like this:
class SignUpView(FormView, LoginErrorView):
form_class = SignUpForm
template_name = "website/sign_up.html"
def form_valid(self, form):
User.objects.create_user(username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password'])
....
The Profile model looks like this:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
initials = models.CharField(max_length=3)
....
I'm creating the profile like this:
#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()
What I would like to do is to save initials in post_save/create_user_profile (in the Profile-model) from the SignUpForm when I'm creating the Profile object, but I can't figure out any simple way of doing this. Any ideas?

You can save profile just after saving user. Try this:
class SignUpView(FormView, LoginErrorView):
form_class = SignUpForm
template_name = "website/sign_up.html"
def form_valid(self, form):
user = User.objects.create(username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password'])
Profile.objects.create(user=user, initials=form.cleaned_data['initials'])
Remove post_save. I hope this will work. If not, please comment.

Related

Overwriting save method to create entry in related table automatically django

After registration email with email confirmation is sent to a new user. I created model
UserWithConfirmation with new field is_email_confirmed. I was following this https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#extending-the-existing-user-model.
I want to have UserWithConfirmation created for each new user when user is saved. For now I have sth like this.
from django.db import models
from django.contrib.auth.models import User
class UserWithConfirmation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="user_with_confirmation")
is_email_confirmed = models.BooleanField(default=False)
def __str__(self):
return self.user.username
class User:
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
create_user_with_confirmation(User)
def create_user_with_confirmation(user):
UserWithConfirmation(user=user)
UserWithConfirmation.save()
How to make it works?
Just have UserWithConfirmation extend User
class UserWithConfirmation(User):
is_email_confirmed = models.BooleanField(default=False)
and change the entry when the email is confirmed
I solved my problem using signals
I changed UserWithConfirmation to Profile
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
is_email_confirmed = models.BooleanField(default=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()

Extend User model in Django with jwt authorization

I am trying to extend User model in Django. I already have authorization using jwt Token and I am currently trying to add another field to User model, such as phone number and address.
My views.py looks like this:
class MyObtainTokenPairView(TokenObtainPairView):
permission_classes = (AllowAny,)
serializer_class = MyTokenObtainPairSerializer
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
permission_classes = (AllowAny,)
serializer_class = RegisterSerializer
models.py like this:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone_number = models.IntegerField(blank=False)
address = models.CharField(max_length=500, 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()
In here I'm trying to create another class that will store phone number and address. How can I incorporate my Profile class into User so that it will create new user model and what is more use earlier implemented Token authorization.

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: 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

Saving a extended user profile

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()