用户保存后更新用户个人资料

时间:2017-01-05 08:01:09

标签: django django-models django-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对象的一部分:< / p>

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

我遇到的很多例子都不使用这种方法。使用这种方法有什么警告吗?

3 个答案:

答案 0 :(得分:3)

更好的方法是指定自定义用户模型。

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'

答案 1 :(得分:1)

您可以使用这样的自定义用户模型:

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文件的作用是通知您何时创建了一个用户类型的新Profile对象,您可以将其进一步用于创建更新/创建用户个人资料的表单。

要使所有这些工作正常进行,您需要在应用程序的apps.py文件中导入signals.py文件。例如,这是您的apps.py文件的外观:

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'

    def ready(self):
        import users.signals

答案 2 :(得分:0)

是的,有一些。在以下情况下,不会触发post_save信号。

1如果save方法未成功保存对象(例如发生IntegrityError时)

2致电MyModel.objects.update()

3覆盖save方法时忘记调用超类方法。

4当您的信号接收器尚未成功注册时。

在这些情况下,您的个人资料不会被保存。