【问题标题】:How do I write a Django ORM query for the reverse relationship in a one-to-many relationship?如何为一对多关系中的反向关系编写 Django ORM 查询?
【发布时间】:2019-06-15 00:34:57
【问题描述】:

我正在使用 Django 和 Python 3.7。我的 models.py 文件中有以下两个模型...

class Article(models.Model):
    created_on = models.DateTimeField(default=datetime.now)
...


class ArticleStat(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, )
    elapsed_time_in_seconds = models.IntegerField(default=0, null=False)

我想编写一个 Django ORM 查询,其中我选择的文章具有至少 5 分钟(300 秒)旧的统计信息。但是,我不知道如何从 Article 对象中引用 ArticleStat 对象。不出所料,这个

Article.objects.filter(articlestat.elapsed_time_in_seconds.lte==300)

产生一个

NameError: name 'articlestat' is not defined

错误。

编辑:根据答案,我将我的 ArticleStat 模型更改为

class ArticleStat(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')

然后我运行了下面的查询来显示错误

Article.objects.filter(articlestat_set__elapsed_time_in_seconds__lte==300)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'articlestat_set__elapsed_time_in_seconds__lte' is not defined

我想也许有一个实例有多个,所以我尝试了一个“s”,但得到了一个错误..

Article.objects.filter(articlestats_set__elapsed_time_in_seconds__lte==300)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'articlestats_set__elapsed_time_in_seconds__lte' is not defined

【问题讨论】:

    标签: python sql django python-3.x orm


    【解决方案1】:

    这里的核心问题是NameError 对应articlestat,所以我将首先解决这个问题。

    正如django documentation 中所解释的,您的后向关系名称默认定义为FOO_set,在您的情况下意味着articlestat_set。

    如果模型有ForeignKey,则外键模型的实例 将有权访问返回所有实例的Manager 第一个模型。默认情况下,这个Manager 被命名为FOO_set, 其中 FOO 是源模型名称,小写。

    如果您喜欢不同的名称,可以通过在 ForeignKey 定义中指定 related_name 来实现,例如

    class ArticleStat(models.Model):
        article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')
        elapsed_time_in_seconds = models.IntegerField(default=0, null=False)
    

    第二个问题是如何正确遵循关系,这在here 中得到了相当广泛的解释,这就是为什么我不会在这个答案中详细介绍它的原因。要点是您要使用__(双下划线)而不是. 运算符。 field lookups 也是如此,您需要在此查询中进行比较。

    解决这两个问题后,您的查询应如下所示:

    Article.objects.filter(articlestat_set__elapsed_time_in_seconds__lte=300)
    

    或使用自定义 related_name 例如related_name='articlestats':

    Article.objects.filter(articlestats__elapsed_time_in_seconds__lte=300)
    

    【讨论】:

    • 非常好的答案。解释得很好。
    • @FynnBecker,感谢您的详尽解释。我一定遗漏了一些非常明显的东西,因为我在我的 ArticleStat 模型中添加了“related_name='articlestats'”,然后我运行了查询,用“articlestat”替换了“FOO”,但是得到了错误“NameError: name 'articlestat_set__elapsed_time_in_seconds__lte' is not定义”。我还将输出放在我的问题中。
    • @Dave 如果您选择使用自定义 related_name,您现在必须在查询中使用它而不是 FOO_set(这只是默认设置如果您不指定 related_name)。我已经更新了答案以包含一个示例。
    【解决方案2】:

    尝试类似:

    Article.objects.filter(articlestat__elapsed_time_in_seconds__lte=300)

    请注意,Django 查询的工作方式类似于 keywords (kwargs)(即您只能将 filter_string=something 传递给过滤器函数)。

    您传递了一个 python 无法解析的表达式(即 python 试图找到 articlestat 变量名,然后获取它的 elapsed_time_in_seconds 属性等)

    看看这个https://docs.djangoproject.com/en/2.1/topics/db/queries/#retrieving-specific-objects-with-filters

    【讨论】:

    • 这导致了错误,“NameError: name 'articlestat__elapsed_time_in_seconds__lte' is not defined”。请注意,在我的模型中定义的 ArticleStat 模型与 Article 具有一对一的关系,但反之则不然。这是我问题的根源。
    猜你喜欢
    • 2019-05-18
    • 1970-01-01
    • 2019-04-22
    • 2016-09-15
    • 2023-04-01
    • 1970-01-01
    • 2014-07-14
    • 2012-09-18
    • 1970-01-01
    相关资源
    最近更新 更多