Catching some values in django signals - django

I'm using django signals to catching some values. My example:
#receiver(post_save, sender=Profile)
def my_example(sender, instance, created, **kwargs):
if created:
user_id = instance.user.id
level = instance.is_admin
company = instance.company
I need to catch user_id, level and company. But only user_id contains value. company value is always None and level is always False.
This is my basic model for profile:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
is_supervisor = models.BooleanField("Supervisor", default=False)
is_admin = models.BooleanField("Admin", default=False)
company = models.ForeignKey(
"core.company",
related_name="users",
on_delete=models.CASCADE,
blank=True,
null=True,
)
def __str__(self):
"""Unicode representation of MyUser."""
return self.user
#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()
And a simple test to pass values:
def test_example:
company = Company.objects.create(name="company1")
user_test = User.objects.create(username="user_test")
user_test.profile.company = company
user_test.profile.is_admin = True
user_test.profile.save()
user_test.save()
And the result:
user_id = user_test
company = None
level = False

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

(1048, "Column 'user_id' cannot be null") with Django DRF

I wrote code to create new users via POST and DRF (Django Rest Framework) successfully and I can obtain token correctly, however when I try to POST (via DRF) to fill Profile linked to that user I get
(1048, "Column 'user_id' cannot be null")
This is snippets of my code:
for serializers:
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ('username','email','first_name','last_name','password')
def create(self, *args, **kwargs):
user = super().create(*args, **kwargs)
p = user.password
user.set_password(p)
user.save()
return user
def update(self, *args, **kwargs):
user = super().update(*args, **kwargs)
p = user.password
user.set_password(p)
user.save()
return user
class ProfileSerializer(ModelSerializer):
class Meta:
model = Profile
fields = ('bio','birth_date','location','country')
def create(self, *args, **kwargs):
profile = super().create(*args, **kwargs)
profile.save()
return profile
def update(self, *args, **kwargs):
profile = super().update(*args, **kwargs)
profile.save()
return profile
and for views:
class ProfileViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
permission_classes = IsAuthenticated,
serializer_class = ProfileSerializer
queryset = Profile.objects.all()
class UserViewSet(viewsets.GenericViewSet,mixins.CreateModelMixin,):
"""
API endpoint that allows users to be viewed or edited.
"""
#permission_classes= (IsAdminUser,)
serializer_class = UserSerializer
queryset = User.objects.all().order_by('-date_joined')
and for models:
#receiver(post_save, sender = settings.AUTH_USER_MODEL)
def create_auth_token(sender,instance=None,created=False, **kwargs):
if created:
Token.objects.create(user=instance)
class Country(models.Model):
iso = models.CharField(max_length = 2,unique = True)
name = models.CharField(max_length = 250)
iso3 = models.CharField(max_length = 6)
phonecode = models.CharField(max_length=6)
def __unicode__(self):
return '%s' % self.name
def __str__(self):
return '%s' % self.name
class Profile(models.Model):
#user = models.OneToOneField(User, on_delete=models.CASCADE,default = "")
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default = "")
bio = models.TextField(max_length=100, blank=True)
birth_date = models.DateField(null=True, blank=True)
location = models.CharField(max_length=254, blank=True)
country = models.ForeignKey(Country,on_delete=models.CASCADE,blank=True,null=True)
def __unicode__(self):
return '%s' % self.user
def __str__(self):
return '%s' % self.user
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
When I try with Postman and I pass a token for token authentication, it recognize the token correctly but I get this error:
(1048, "Column 'user_id' cannot be null") with Django DRF
I appreciate your help to solve this problem
Create() save to the database, so you need to set profile.user_id before calling the function.

Django IntegrityError on profile creation

Why am I getting the Integrity Error despite the fact that I'm checking that the username is unique here:
(I also tried try/expect IntegretyError instead of e.count())
# -*- coding: utf-8 -*-
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 slugify import slugify
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
username = models.CharField(max_length=30, blank=True, unique=True) #should be true on signup
name = models.CharField(max_length=30, blank=True)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
email = models.EmailField() #should be true on signup
avatar_url = models.URLField(default="https://image.flaticon.com/icons/png/512/64/64572.png")
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(commit=False)
from allauth.account.signals import user_logged_in, password_set, user_signed_up
from django.db.models.signals import post_save
from django.dispatch import receiver, Signal
#receiver(user_logged_in)
def populate_profile(sociallogin, user, **kwargs):
# picture_url = ""
if sociallogin.account.provider == 'github':
user_data = user.socialaccount_set.filter(provider='github')[0].extra_data
print(user_data)
username = user_data['login']
avatar_url = user_data['avatar_url']
email = user_data['email']
name = user_data['name']
bio = user_data['bio']
location = user_data['location']
if sociallogin.account.provider == 'twitter':
user_data = user.socialaccount_set.filter(provider='twitter')[0].extra_data
print(user_data)
username = user_data['screen_name']
avatar_url = user_data['profile_image_url'].replace("_normal", "")
email = user_data['email']
name = user_data['name']
bio = user_data['description']
location = user_data['location']
e = Profile.objects.filter(username=username)
if e.count() > 0:
user.profile.username = slugify(name)
else:
user.profile.username = username
#except IntegrityError:
user.profile.avatar_url = avatar_url
user.profile.email = email
user.profile.name = name
user.profile.bio = bio
user.profile.location = location
user.profile.save()
Well, probably this line of code is the issue:
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
# if created:
Profile.objects.create(user=instance) # <---
Because, every-time user is saved, this signal will be triggered, hence will try to create a profile. Instead, use the commented out code section:
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
Then only if the a user is created, then a profile will be created.
Also I am not sure if the following code will work. Because model's save() method does not have any keyword argument named commit. So it might throw error.
To be honest, you don't need that signal, so you can remove that as well.

django customuser matching query does not exist

I think it originates in this view, since it's being transfered to the home view (see below):
#login_required
def HomePage(request):
if request.user.get_profile().phone == "":
return HttpResponseRedirect('/phone')
else:
add_list = add.objects.all()
ctx = {'last_login':request.session.get('social_auth_login_backend')}
return render_to_response("homepage.html", {'add_list': add_list, 'ctx':ctx}, context_instance=RequestContext(request))
And the model:
class customuser(models.Model):
last_login = models.DateTimeField(blank=True, null=True)
is_active = models.BooleanField()
nickname = models.CharField(max_length=255)
regdate = models.DateField(auto_now=True)
phone = models.CharField(max_length=255)
user = models.OneToOneField(User)
city = models.ForeignKey(locations, null=True)
def __str__(self):
return "%s user " % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = customuser.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
class Admin:
pass
I'm not sure if this is the cause of you're problem, but the context dictionary that you're passing to your template looks wrong. The view should probably be re-written -
def HomePage(request):
if request.user.get_profile().phone == "":
return HttpResponseRedirect('/phone')
else:
ctx = {'last_login':request.session.get('social_auth_login_backend'),
'add_list': add.objects.all()}
return render(request, "homepage.html", ctx)

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