具有三层深度嵌套模型的查询集过滤器(多个一对多关系)

Posted

技术标签:

【中文标题】具有三层深度嵌套模型的查询集过滤器(多个一对多关系)【英文标题】:Queryset filter with three-deep nested models (multiple one-to-many relationships) 【发布时间】:2017-02-03 07:33:45 【问题描述】:

我试图弄清楚如何使用我的模型设置过滤 Django 中的一些查询:

class Team(models.Model):
    name = models.CharField()

class TeamPosition(models.Model):
    description = models.CharField()
    team = models.ForeignKey(Team)

class Player(models.Model):
    teamposition = models.ForeignKey(TeamPosition)
    team = models.ForeignKey(Team)
    joined_date = models.DateField()
    left_date = models.DateField(blank=True, null=True)
    person = models.ForeignKey(Person)

class Person(models.Model):
    name = models.CharField()

我想找到回答这些问题的查询集(为了清楚起见,移到下面):

如果我从 TeamPosition 对象开始,则更容易弄清楚(但不会给我 Teams 的查询集)。

样本数据集:

对象集 1:

Team(name="Apples")
    TeamPosition(team="Apples", description="Forward")
        Player(team="Apples", teamposition="Forward", joined_date="2014-01-01", left_date=null, person="Bob")
    TeamPosition(team="Apples", description="Defense")
        Player(team="Apples", teamposition="Defense", joined_date="2014-01-01", left_date=2015-01-01, person="John")
        Player(team="Apples", teamposition="Defense", joined_date="2015-01-01", left_date=2017-01-01, person="Paul")
    TeamPosition(team="Apples", description="Goalie")
        Player(team="Apples", teamposition="Goalie", joined_date="2014-01-01", left_date=2015-01-01, person="Jane")

对象集 2:

Team(name="Pears")
    TeamPosition(team="Pears", description="Forward")
        Player(team="Pears", teamposition="Forward", joined_date="2014-01-01", left_date=null, person="Carol")
    TeamPosition(team="Pears", description="Defense")
        Player(team="Pears", teamposition="Defense", joined_date="2015-01-01", left_date=2017-01-01, person="Bill")
    TeamPosition(team="Pears", description="Goalie")
        Player(team="Pears", teamposition="Goalie", joined_date="2014-01-01", left_date=null, person="Susan")

对象集 3:

Team(name="Oranges")
    TeamPosition(team="Oranges", description="Forward")
    TeamPosition(team="Oranges", description="Forward")
    TeamPosition(team="Oranges", description="Goalie")

对象集 4:

Team(name="Bananas")
    TeamPosition(team="Bananas", description="Forward")
        Player(team="Bananas", teamposition="Forward", joined_date="2014-01-01", left_date=null, person="Joe")
    TeamPosition(team="Bananas", description="Defense")
        Player(team="Bananas", teamposition="Defense", joined_date="2015-01-01", left_date=2017-01-01, person="Angela")
    TeamPosition(team="Bananas", description="Goalie")
        Player(team="Bananas", teamposition="Goalie", joined_date="2014-01-01", left_date="2016-09-30", person="Kelly")

因此,基于这些对象,我希望得到以下结果:

哪些团队有可用的团队职位? (可用的意思是没有当前玩家的 TeamPosition)

Queryset should return Object 1 (Apples) and Object 3 (Oranges)

哪些球队的所有 TeamPosition 都已满员? (与上述相反)(当前表示未来没有 left_date 或 left_date 的玩家)

Queryset should return Object 2 (Pears) and Object 4 (Bananas)

哪些团队在 30 天内会有空的 TeamPosition?

Queryset should return Object 4 (Bananas)

希望这样可以更清楚。

注意:以前有一个汽车示例(因此是第一个响应),但似乎不清楚所以创建了一个更好的示例

【问题讨论】:

【参考方案1】:

回答前的一个问题:carmodel = models.ForeignKey(Model) 行好吗?还是应该改成ForeignKey(CarModel)

试试这个查询(这应该会为您提供 CarModel 的 ModelYear 的 last_availability 日期在未来的所有 CarCompany 对象:

from datetime import datetime
CarCompany.objects.filter(carmodel__modelyear__last_availability__gte=datetime.now())

为了检查last_availability 是在未来还是空白/空,我会使用Q objects:

from django.db.models import Q
CarCompany.objects.filter(Q(carmodel__modelyear__last_availability__gte=datetime.now()) |
                          Q(carmodel__modelyear__last_availability__isnull=True))

对于您的第二个示例,我想不出但在同一个查询中(它回答了您的问题 Which Teams have open TeamPositions?Which Teams will have an empty TeamPosition in 30 days

但我不确定Which Teams have no TeamPositions without current Players? 是什么意思,如果你能解释一下...

Team.objects.filter(Q(teamposition__player__left_date__gte=datetime.now()) |
                    Q(teamposition__player__left_date__isnull=True) |

【讨论】:

你说得对,应该是 CarModel。我会试试这个..! 进行了快速测试,删除了exact=''(我认为空白时日期总是为空,django 提醒了我)并添加了 distinct()。然而,我最终得到了我所有的测试对象(应该是大约一半)。我正在编辑我的问题以添加一组不同的示例类,这可能会更清楚。 我不明白为什么该查询不起作用。无论如何,我更新了我的答案。您能否澄清第二个示例中的Which Teams have no TeamPositions without current Players? 是什么意思? 即如果一个团队有 2 个 TeamPlayers,其中一个有一个 Player 对象,其 join_date 为昨天且没有 left_date,但另一个 TeamPlayer 对象要么没有与之关联的 Player,要么有一个 left_date 为去年的 Player。 查询有效...它只返回我所有测试数据的查询集。从理论上讲,它应该只返回 CarCompany 对象,这些对象的 CarModels 和 ModelYears 未来的 last_availability 或 last_availability 为 null。我有一个测试数据,其中有一个带有 CarModel 的 CarCompany 并且没有包含 ModelYear 对象,但是当我创建一个 ModelYear 对象时,该对象在从集合中删除之前很久就过期了。我认为当有多个 CarModel 时它会跳闸。

以上是关于具有三层深度嵌套模型的查询集过滤器(多个一对多关系)的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 混合获取 Eloquent 急切加载嵌套多个模型

嵌套的一对多关系 sqlalchemy 过滤

mybatis一对多双层嵌套查询

GraphQL/Graph.cool 查询过滤嵌套关系

在一对多情况下具有 ID 数组的查询构建器

Django 无法确定使用一对一关系链接一对多的查询集