Overwriting save method to create entry in related table automatically django - 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()

Related

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.

Django signals not working, tried every possible solution

signals.py
#receiver(user_logged_in, sender=User)
def when_user_logs_in(sender, request, **kwargs):
print('user_logs_signal is called')
LoggedInUser.objects.get_or_create(user=kwargs.get('user'))
#receiver(user_logged_out, sender=User)
def when_user_logs_out(sender, request, **kwargs):
print('user logs out signal iscalled')
LoggedInUser.objects.get_or_create(user=kwargs.get('user')).delete()
models.py
class LoggedInUser(models.Model):
user = models.OneToOneField(User, related_name='logged_in_user', on_delete =models.CASCADE, null=True, blank=True)
session_key = models.CharField(max_length=32, null=True, blank=True)
def __str__(self):
return self.user.username
apps.py
class AccountsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "accounts"
def ready(self):
import accounts.signals
I have done anything that i found to solve signals now working but it didnt solve i have even added "accounts.apps.AccountsConfig" in my settings.py but still it not firing i am currently logged_in and using jwt based authentication , needs help

Adding field to Profile when creating User

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.

django: extending user model with one-to-one link - how to use post_save signal

I am new to django , I am learning how to extend the user model using the following site:
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
I have some doubt in the following model:
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()
How this line exactly works:
Profile.objects.create(user=instance)
I know post_save will be called after user is created, but I don't understand how the following line is used to store the additional fields.
Profile.objects.create(user=instance)

'RelatedManager' object has no attribute 'save'

This is the models.py code
class Profile(models.Model):
user = models.ForeignKey(User, unique=True, on_delete=models.CASCADE, related_name='profile')
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
# Profile.objects.save()
instance.profile.save()
and This the views.py code:
def signup(request):
....
if request.method == "POST":
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
user = user_form.save(commit=False)
user.save(using='default')
login(request, user)
return HttpResponse("User Loged In")
Then after fill the registration form and click the submit button, Django get me the following Error:
You defined a ForeignKey from a Profile to a User, but that means every Profile is attached to a User, it is however perfectly possible that multiple Profiles are attached to the same User.
Hence if you use a_user.profile, it will not return a single Profile, but a RelatedManager: a manager that manages the collection (that can contain zero, one or multiple elements) of Profile.
I think however that you actually want to associated Profiles with distinct Users, in which case you better use a OneToOneField:
class Profile(models.Model):
user = models.OneToOneField(User, unique=True, on_delete=models.CASCADE)
If you then query someuser.profile you will either get a Profile instance, or it will raise a Profile.DoesNotExists error in case no profile is associated with that user.
By default the related_name of a OneToOneField is the name of the class in lowercase, so you no longer need to specify this.
Note however that in your code instance.profile.save() is not necessary, since the Profile, is basically already saved by creating it:
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
# unnecessary
# instance.profile.save()