在用户保存时更新用户配置文件

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