在用户保存时更新用户配置文件
Updating the a user profile upon user save
我正在按照 'User profile' 方法扩展我的用户模型,如下所示:
# models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE, primary_key=True)
my_field = models.CharField(max_length=100)
# signals.py
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
使用这种方法,我必须显式调用 user.profile.save()
,这对我来说感觉很笨拙,因为我希望 profile
给人一种错觉,它是 User
对象的一部分:
# views.py
def some_func(request):
user = User.objects.create_user('dummy', 'dummy@dummy.com', '12345678')
user.profile.my_field = 'hello'
user.save() # This does not persist the profile object...
user.profile.save() # ...this does
为了解决这个问题,我已将 create_user_profile()
更改为以下有效的内容:
# signals.py
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
profile = UserProfile.objects.get_or_create(user=instance)
profile.save()
我遇到的许多例子都没有使用这种方法。使用这种方法有什么注意事项吗?
是的,有几个。在以下情况下 post_save 信号不会被触发。
1 如果save方法没有成功保存对象(比如发生IntegrityError时)
2 当您调用 MyModel.objects.update()
3当你重写save方法而忘记调用超类方法时
4 当你的信号接收器没有注册成功时。
在这些情况下,您的个人资料将不会保存。
更好的方法是指定自定义用户模型。
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
custom_field = models.ForeignKey(
'contracts.Contract'
)
...
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
您必须更新 settings.py
定义 AUTH_USER_MODEL
属性:
AUTH_USER_MODEL = 'app_name.User'
您可以像这样使用自定义用户模型:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return f'{self.user.username} Profile'
然后是 signals.py 文件:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
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()
signals.py 文件在这里的作用是在创建用户类型的新配置文件对象时通知您,您可以进一步使用它来创建 update/create 用户配置文件的表单。
要完成所有这些工作,您需要将 signals.py 文件导入到应用程序的 apps.py 文件中。例如,这是您的 apps.py 文件的样子:
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
我正在按照 'User profile' 方法扩展我的用户模型,如下所示:
# models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE, primary_key=True)
my_field = models.CharField(max_length=100)
# signals.py
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
使用这种方法,我必须显式调用 user.profile.save()
,这对我来说感觉很笨拙,因为我希望 profile
给人一种错觉,它是 User
对象的一部分:
# views.py
def some_func(request):
user = User.objects.create_user('dummy', 'dummy@dummy.com', '12345678')
user.profile.my_field = 'hello'
user.save() # This does not persist the profile object...
user.profile.save() # ...this does
为了解决这个问题,我已将 create_user_profile()
更改为以下有效的内容:
# signals.py
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
profile = UserProfile.objects.get_or_create(user=instance)
profile.save()
我遇到的许多例子都没有使用这种方法。使用这种方法有什么注意事项吗?
是的,有几个。在以下情况下 post_save 信号不会被触发。
1 如果save方法没有成功保存对象(比如发生IntegrityError时)
2 当您调用 MyModel.objects.update()
3当你重写save方法而忘记调用超类方法时
4 当你的信号接收器没有注册成功时。
在这些情况下,您的个人资料将不会保存。
更好的方法是指定自定义用户模型。
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
custom_field = models.ForeignKey(
'contracts.Contract'
)
...
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
您必须更新 settings.py
定义 AUTH_USER_MODEL
属性:
AUTH_USER_MODEL = 'app_name.User'
您可以像这样使用自定义用户模型:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return f'{self.user.username} Profile'
然后是 signals.py 文件:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
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()
signals.py 文件在这里的作用是在创建用户类型的新配置文件对象时通知您,您可以进一步使用它来创建 update/create 用户配置文件的表单。
要完成所有这些工作,您需要将 signals.py 文件导入到应用程序的 apps.py 文件中。例如,这是您的 apps.py 文件的样子:
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals