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_or_create

覆盖不适用于静态方法

覆盖django的model delete方法进行批量删除

如何在 Django 中覆盖“get_queryset()”

Kotlin:尝试在 WebView 上添加 onReceivedError 时出现“修改器‘覆盖’不适用于‘本地函数’”错误