【问题标题】:Django, query filtering from model methodDjango,来自模型方法的查询过滤
【发布时间】:2011-01-17 14:52:05
【问题描述】:

我有这些模型:

def Foo(Models.model):
    size = models.IntegerField()
    # other fields

    def is_active(self):
         if check_condition:
              return True
         else:
              return False

def Bar(Models.model):
     foo = models.ForeignKey("Foo")
     # other fields

现在我想查询具有活动 Foo 的 Bars:

Bar.objects.filter(foo.is_active())

我收到诸如

之类的错误
SyntaxError at /
('non-keyword arg after keyword arg'

我怎样才能做到这一点?

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    您不能查询模型方法或属性。要么在查询中使用其中的条件,要么在 Python 中使用列表推导或genex 进行过滤。

    【讨论】:

    • 或者将您想要过滤的值存储在数据库字段中,并在需要时更新它(通常在保存时)。然后,您可以像任何其他字段一样对其进行过滤/排序。
    • 如果我在方法查询中重复使用条件,我如何保持 DRY?我的方法对我们的业务逻辑非常重要,如果所述逻辑发生变化,我无法承受我的方法中断。保持干爽非常重要。
    【解决方案2】:

    您也可以使用自定义管理器。然后你可以运行这样的东西:

    Bar.objects.foo_active()
    

    而你所要做的就是:

    class BarManager(models.Manager):
        def foo_active(self):
           # use your method to filter results
           return you_custom_queryset
    

    查看docs

    【讨论】:

    • 我强调这种方法会阻止查询集链接:无法在自定义管理器中运行 python,然后添加查询集方法,例如 filterexclude。这样做的原因是,当您在其上运行非查询集方法时,Django 将评估查询集。查询集由 SQL 命令组成,这些命令将从数据库中获取查询的数据。在此示例中,如果 Django 没有评估查询集以从数据库中获取数据,则此自定义管理器中的 python 方法将没有可交互的数据。
    • @TD1 这句话很有价值。从技术上讲,我会说这种自定义管理器方法不会阻止您使用查询集链接,因为您仍然可以将它用作链中的终端方法。但您必须牢记这一点,以免出错。
    【解决方案3】:

    我有类似的问题:我正在使用基于类的视图object_list,我必须按模型的方法进行过滤。 (将信息存储在数据库中不是一种选择,因为该属性是基于时间的,我必须创建一个 cronjob 和/或...没办法

    我的回答是无效的,我不知道它会如何扩展到更大的数据;但是,它有效:

    q = Model.objects.filter(...)...
    # here is the trick
    q_ids = [o.id for o in q if o.method()]
    q = q.filter(id__in=q_ids)
    

    【讨论】:

    • 这是我认为保持 DRY 的唯一方法,但是它会影响较大数据集的性能(请记住,列表存储在内存中)
    【解决方案4】:

    您不能过滤方法,但是如果 Foo 上的 is_active 方法检查 Foo 上的属性,您可以使用双下划线语法,如 Bar.objects.filter(foo__is_active_attribute=True)

    【讨论】:

    • 我得到:无法将关键字“is_active_attribute”解析为字段选择是:....此处列出的所有变量名称
    • 是的,这就是为什么我说“如果 Foo 上的 is_active 方法检查一个属性......”。过滤仅适用于数据库字段,不适用于方法。因此,如果 is_active 正在检查方法内的某些属性,您可以在过滤器中检查相同的内容。如果它正在做一些更复杂的事情,那么你就不走运了,需要找到不同的解决方案。如果您想要一个具体的答案,请发布 Foo.is_active() 的真实代码。否则,您将得到的只是伪代码解决方案,您不应该期望逐字逐句地工作。
    【解决方案5】:
    class Page(models.Model):
        category = models.ForeignKey(Category)
        title = models.CharField(max_length=128)
        url = models.URLField()
    ...
    
    class Category(models.Model):
        ...
        open = models.BooleanField(default=True)
    

    对于这种情况,您可以使用简单的过滤器。

    Page.objects.filter(category__open=True)
    

    【讨论】:

      猜你喜欢
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      • 2016-11-22
      • 1970-01-01
      • 2010-11-30
      • 2015-07-16
      • 2021-08-05
      相关资源
      最近更新 更多