Django中create()未应用管理器注解,如何强制使用自定义管理器?
Django 让 create() 使用自定义管理器的解决方案
问题背景
现有如下模型、管理器及QuerySet定义:
from django.db import models from django.db.models import Value # 补充原代码遗漏的导入 class BlaQuerySet(models.QuerySet): def annotate_field(self): return self.annotate(bla_field=Value('Bla')) class BlaManager(models.Manager): def get_queryset(self): return BlaQuerySet(self.model, using=self._db).annotate_field() class Bla(models.Model): hello = models.CharField(max_length=10) objects = BlaManager()
遇到的问题:
- 调用
Bla.objects.create(hello='something')创建实例后,访问bla_instance.bla_field会抛出AttributeError: 'Bla' object has no attribute 'bla_field' - 但调用
Bla.objects.get(hello='something')查询实例时,bla_instance.bla_field能正常返回预期值Bla - 设置
Meta.base_manager_name = 'objects'也无法解决问题
原因分析
Django 的 create() 方法逻辑是先在内存中生成模型实例,再保存到数据库,这个过程不会经过自定义管理器 get_queryset() 中的注解流程——因为注解是 QuerySet 层面的数据库查询操作,并非模型实例本身的字段。而 get() 是从数据库执行查询,会触发自定义管理器的 QuerySet 逻辑,因此能带上注解字段。
解决方案
1. 重写管理器的 create 方法
在自定义管理器中重写 create(),创建实例后重新查询一次,确保返回带注解的实例:
class BlaManager(models.Manager): def get_queryset(self): return BlaQuerySet(self.model, using=self._db).annotate_field() def create(self, **kwargs): # 调用父类方法创建并保存实例 instance = super().create(**kwargs) # 通过自定义管理器重新查询,获取带注解的实例 return self.get(pk=instance.pk)
之后调用 Bla.objects.create() 时,返回的就是包含 bla_field 的实例。
2. 在模型中添加属性动态返回值
如果 bla_field 是固定值,直接在模型类中定义 @property 属性,无需依赖 QuerySet 注解:
class Bla(models.Model): hello = models.CharField(max_length=10) objects = BlaManager() @property def bla_field(self): return 'Bla'
这种方式下,无论实例是创建还是查询而来,都能直接访问 bla_field。
3. 创建后手动查询实例
如果不想修改管理器或模型,也可以在 create() 之后手动执行一次查询:
bla_instance = Bla.objects.create(hello='something') # 重新查询获取带注解的实例 bla_instance = Bla.objects.get(pk=bla_instance.pk) print(bla_instance.bla_field) # 正常返回 'Bla'
内容的提问来源于stack exchange,提问作者S.D.
相关产品推荐
相关产品推荐

