保存后更新实例,在某些情况下通过有条件地引用回实例使用信号

Update the instance after save, using signals by conditionally refference back to the instance in some cases

我有以下摘要class:

class UserStamp(models.Model):
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
                                   related_name='%(app_label)s_%(class)s_created_by', on_delete=models.CASCADE)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
                                   related_name='%(app_label)s_%(class)s_updated_by', on_delete=models.CASCADE)

    class Meta:
        abstract = True

我有一个继承自 User 的自定义用户。

class User(AbstractBaseUser,PermissionsMixin, UserStamp):
    account = models.ForeignKey(Account, blank=True, null=True, related_name='owner',on_delete=models.CASCADE)

用户可以create/update自己或其他用户。

当用户create/update本人我没有任何东西created_by,update_by.

用户可以使用Django Admin创建,也可以在Django Admin之外创建;

在Django Admin中用户可以由工作人员创建,在Django之外是自己创建的;

还有在终端中创建的超级用户;

关于更新,Django Admin 和外部的用户都可以自行更新或由其他用户更新。

我考虑过使用 post_save 或自定义信号。问题是 request.user 在模型中不可用,但在视图中可用,并且在管理员和终端(超级用户)中控制视图是一个瓶颈。

也许在保存通过实例后尝试进行查询,但我不完全知道如何将所有这些组合起来signal/query,检查超级用户。

创建您自己的 custom signals

signals.py

from django.dispatch import Signal 
# you can pass any number of arguments as per your requirement.
manage_user = Signal(providing_args=["user", "is_updated"])


def user_handler(sender, **kwargs):
    # `user` who created/updated object i.e `request.user`
    user = kwargs['user']
    # `is_updated` will be `False` if user object created.
    is_updated = kwargs['is_updated']
    # `sender` is the user object which is created/updated.
    ...
    # do your stuff

manage_user.connect(user_handler)

models.py

覆盖自定义用户 class 的 save() 方法。

from .signals import manage_user

class User(...):
    ...
    # call this save method like obj.save(created_by=request.user)
    def save(self, created_by, *args, **kwargs):
        super().save(*args, **kwargs)
        # is_updated will be True if user object is updated 
        manage_user.send(sender=self, user=created_by, is_updated=True if self.id else False)

send manage_user signal when user model changed, just like post_save signal, but now you have control over parameters.

更新

如果您使用 django admin 创建用户,您可以覆盖 save_model,那里有请求对象。

from django.contrib import admin

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
     def save_model(self, request, obj, form, change):
         super(UserAdmin, self).save_model(request, obj, form, change)
         manage_user.send(sender=self, user=request.user, is_updated=True if self.id else False)