在Django中过滤带继承的模型

时间:2009-07-30 23:56:18

标签: django django-models

我有两个Django模型类,其结构类似于以下内容:

class Build(models.Model):
    project = models.CharField(max_length=100)
    ...

class CustomBuild(Build):
    custom_type = ...
    ...

我想从具有特定项目属性的数据库中选择所有Builds CustomBuilds(每个CustomBuild与Build具有一对一的关系)。

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

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

2 个答案:

答案 0 :(得分:4)

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

我用得很多的“简单而愚蠢”的方式是用效用函数来管理结果。例如,如果您计划在模板中处理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片段。但请注意,几乎任何这样的解决方案都会受到性能限制。

答案 1 :(得分:1)

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

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