Django覆盖模型get()方法不适用于外键
Posted
技术标签:
【中文标题】Django覆盖模型get()方法不适用于外键【英文标题】:Django override model get() method won't work on foreign keys 【发布时间】:2021-05-22 23:05:16 【问题描述】:我有一个自定义模型定义如下,get()
方法覆盖
class CustomQuerySetManager(models.QuerySet):
def get(self, *args, **kwargs):
print('Using custom manager')
# some other logics here...
return super(CustomQuerySetManager, self).get(*args, **kwargs)
class CustomModel(models.Model):
objects = CustomQuerySetManager.as_manager()
class Meta:
abstract = True
然后我有两个模型定义为
class Company(CustomModel):
name = models.CharField(max_length=40)
class People(CustomModel):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
如果我像People.objects.get(pk=1)
一样直接使用get()
,那么它可以工作,“使用自定义管理器”会打印出来,但是如果我尝试获取外键信息,django 仍然使用默认管理器中的get()
方法,例如,没有打印任何内容,并且定义的其余逻辑将不会被执行
someone = People.objects.get(id=1) # prints Using custom manager, custom logic executed
company_name = someone.company.name # nothing gets printed, custom logic does not execute
即使外键模型也使用我的自定义模型类,模型中的外键字段是否使用不同的管理器?有没有办法让我的自定义 get()
方法适用于所有字段?
【问题讨论】:
【参考方案1】:正如 django 文档所说
默认情况下,Django 使用 Model._base_manager 管理器的实例 访问相关对象(即choice.question)时的类,而不是 _default_manager 在相关对象上
查看更多here。
所以你必须告诉 django model 使用哪个管理器作为基础管理器,像这样:
class CustomModel(models.Model):
objects = CustomQuerySetManager.as_manager()
class Meta:
#django will use your custom "objects" manager as base_manager
#or you may have different managers for base and default managers
#if you define two managers with different names
base_manager_name = 'objects'
abstract = True
但是,请注意不要过滤掉来自基本经理的任何结果。 Django 文档说:
此管理器用于访问与某些对象相关的对象 其他型号。在这些情况下,Django 必须能够看到所有 它正在获取的模型的对象,因此任何 引用的可以检索。
因此,不要为此类经理覆盖get_queryset()
。
查看更多here。
【讨论】:
以上是关于Django覆盖模型get()方法不适用于外键的主要内容,如果未能解决你的问题,请参考以下文章
关于覆盖外键表单小部件以接收用户输入的 Django 最佳实践
如何在 Django 中覆盖“get_queryset()”
Kotlin:尝试在 WebView 上添加 onReceivedError 时出现“修改器‘覆盖’不适用于‘本地函数’”错误