在 Django 中使用继承过滤模型

Posted

技术标签:

【中文标题】在 Django 中使用继承过滤模型【英文标题】:Filtering models with inheritance in Django 【发布时间】:2010-11-15 15:38:04 【问题描述】:

我有两个结构类似于以下的 Django 模型类:

类构建(models.Model):
    项目 = models.CharField(max_length=100)
    ...

类自定义构建(构建):
    自定义类型 = ...
    ...

我想从具有特定项目属性的数据库中选择所有构建自定义构建(每个自定义构建与构建具有一对一的关系)。

我相信 Build.objects.filter(project="myproject") 会选择正确的对象,但其中许多会丢失由 CustomBuild 对象提供的附加数据(例如 custom_type)。另一方面,过滤 CustomBuild.objects 将排除那些不是 CustomBuilds 的对象。

我怎样才能做到这一点?谢谢。

【问题讨论】:

【参考方案1】:

您可以采取几种方法来处理执行此类查询时获得的“混合模型”QuerySets。很大程度上取决于您的最终目标。

我经常使用的“简单而笨拙”的方法是使用实​​用函数来管理结果。例如,如果您计划在模板中处理Build.objects.filter(project="myproject") 的结果,您可以使用自定义模板标签或过滤器来采取特殊操作。假设在下面的代码中build_objects 包含您的 filter() 的结果:

% for build in build_objects %
   % if build|is_custom_build %
      <p>This is a custom build of custom type  build.custom_build.custom_type !</p>
   % endif %
   <p>This is a custom build OR a standard build</p>
% endfor %

这里明显的问题是,如果您有许多子类,编写模板过滤器可能不切实际或变得乏味。但是,根据我的经验,我通常最多有六个子类,所以这并不总是一个问题。

您也可以像这样编写参数化过滤器:

% if build|is_of_buildtype:"custom_build" %

过滤器代码如下:

def is_of_buildtype_filter(value, arg):
    if hasattr(value, arg): return True
    else: return False

此过滤器仅检查参数是否作为build 对象上的属性(以value 传递)。参数字符串应该是您要检测的自动生成的OneToOneField 的名称,在本例中为custom_build

对于视图代码,类似的辅助函数可以以相同的方式工作,但更简单,因为您不需要编写自定义过滤器或标签。

这种方法在许多情况下都有效,但在更复杂的情况下可能不实用。不幸的是,当您对基类执行操作时,Django 无法原生地为您提供包含子类实例的QuerySet(即真正包含“混合模型”的QuerySet)。在无法使用辅助函数处理结果的情况下,您可能需要这样做。

我个人完全避免了这些情况,通常是通过重新思考我的模型设计。但如果这不可能,那么有很多有趣的解决方案尝试,比如Inheritance MixIn。还有几个关于这个主题的 Django sn-ps。但请注意,几乎所有此类解决方案都会受到性能限制。

【讨论】:

感谢您花时间撰写此评论。不过,我真的对如何在代码而不是模板中执行此操作更感兴趣。我希望我能接受这两个答案,因为我发现你的 hasattr 代码很有用,但我赞成你的答案。【参考方案2】:

您可以使用 Build.objects.filter() 获取构建对象并在需要时访问子类:

qs = Build.objects.all()
build_obj = qs[4]
custom_build_obj = build_obj.custom_build
custom_build_obj.custom_type = ...

【讨论】:

以上是关于在 Django 中使用继承过滤模型的主要内容,如果未能解决你的问题,请参考以下文章

Django:在使用模板继承时在基本模板文件中加载自定义过滤器时出现问题

使用 F 和 Q 表达式进行 Django 模型过滤

使用可变数量的参数过滤多个 Django 模型字段

使用 Ajax 按钮过滤 Django 模型

Django:过滤管理模板中的空模型条目

尝试使用 django 过滤器为给定模型中的所有字段创建一般搜索