保存Django模型时如何强制要求传入updater_id等指定字段的值
解决方案
最优兼容方案:重写save方法+参数校验
首先优化你的模型字段命名(Django的ForeignKey会自动生成_id后缀的数据库字段,无需手动加后缀):
from django.db import models from django.contrib.auth.models import User class MyModel(models.Model): updater = models.ForeignKey(User, on_delete=models.CASCADE) # 其他字段
重写save方法,从kwargs中提取updater参数,同时兼容原生ORM调用逻辑:
def save(self, *args, **kwargs): # 优先从参数中取updater,覆盖实例原有值 updater = kwargs.pop("updater", None) if updater is not None: self.updater = updater # 强制校验updater不能为空 if not self.updater_id: raise ValueError("保存MyModel实例时必须传入updater参数") super().save(*args, **kwargs)
该方案完美兼容所有Django原生ORM方法:
- 直接调用save:
obj.save(updater=当前用户实例) - 调用create:
MyModel.objects.create(updater=当前用户实例, 其他字段=xxx)(create方法会先把参数赋值给实例再调用save,实例已有updater值不会触发异常) - 调用update_or_create:
MyModel.objects.update_or_create( 过滤字段=xxx, defaults={"其他字段": "xxx", "updater": 当前用户实例} ) - 同用户多次编辑场景:无需修改updater值时直接传原有值即可,不会触发异常。
进阶严格管控:自定义模型管理器
如果需要管控批量更新、批量创建等不会触发单个实例save的操作,可以自定义模型管理器,重写所有ORM操作方法强制校验updater参数:
class MyModelManager(models.Manager): def create(self, **kwargs): if "updater" not in kwargs: raise ValueError("create方法必须传入updater参数") return super().create(**kwargs) def update(self, **kwargs): if "updater" not in kwargs: raise ValueError("update方法必须传入updater参数") return super().update(**kwargs) def update_or_create(self, defaults=None, **kwargs): defaults = defaults or {} if "updater" not in defaults and "updater" not in kwargs: raise ValueError("update_or_create方法必须传入updater参数") return super().update_or_create(defaults=defaults, **kwargs) # 在MyModel中替换默认管理器 class MyModel(models.Model): updater = models.ForeignKey(User, on_delete=models.CASCADE) objects = MyModelManager() # 其他字段和save方法同上
可选优化:自动填充当前用户
如果所有操作都在Web请求上下文内,可以通过自定义中间件存储当前登录用户,在save方法中自动获取填充,无需每次手动传参,注意非请求场景(比如celery任务、命令行脚本)需要手动赋值。
内容的提问来源于stack exchange,提问作者Shmuelt
相关产品推荐
相关产品推荐

