【问题标题】:Chaining queries through related objects通过相关对象链接查询
【发布时间】:2015-10-12 18:14:58
【问题描述】:

给定这样的场景:

from django.db import models

class Player(models.Model):
    playername = models.CharField()

class Team(models):
    teamname = models.CharField()

class Members(models):
    player = models.ForeignKey(Player)
    team = models.ForeignKey(Team)

class Division(models):
    divname = models.CharField()  

class DivisionTeam(models):
    division = models.ForeignKey(Division)
    team = models.ForeignKey(Team)

如何列出部门 id = 5 中的所有不同玩家?我已经查看了 Q 和 F 表达式,但我不是在寻找一组复杂的或。我想知道是否有一种方法可以链接多个object1_set.object2_set.all() 类型结构,或者我是否设置了一个嵌套循环来构建对象(通过上下文传递给模板),最终在模板中使用{% for p in players %} 类型循环. div id 作为请求变量传递。

【问题讨论】:

  • 呃,Player.objects.filter(members__team__divisionteam__divsion__pk=5)?或类似的东西?您的数据库结构令人困惑:P
  • 我假设您使用“不同”一词,出于某种原因,您有多个同名玩家,这就是问题的症结所在?你有什么理由不能只使用 .distinct() 吗?否则,我真的无法告诉你在这里问什么。
  • @NightShadeQueen 它是继承的(但我发挥了作用),基于现有的数据库,并针对这个问题进行了简化。谢谢,我试试看。
  • @foobarbecue 与众不同,因为我尝试过的其他一些事情会多次列出同一名球员,因为他们多年来出现在不止一支球队中。我已经阅读过 distinct() 的内容,但无法直截了当地使用它。
  • 好的,我现在看到 Members 是 Team 和 Player 之间的中间模型。这实际上是有道理的——您可能希望将数据存储在 Member 中,例如玩家成为团队成员的日期。但是你的数据库中不应该有任何重复的玩家对象,所以你不需要 distinct() - 你只需要过滤。

标签: django


【解决方案1】:

你可以这样做:

players = Player.objects.filter(members__team__divisionteam__division_id=5).distinct()

当然,正如另一个答案中所建议的,您的模型可以简化(通过使用 ManyToMany 而不是显式管理它)

【讨论】:

  • 谢谢。作为一个侧栏,如果订单稍微偏离,可以预期“关系字段不支持嵌套查找”错误。结构很难改变,因为有些部分是另一个数据库的视图;并且在某些情况下,中间表中会添加日期有效类型信息。仍然掌握 Django 的窍门,但喜欢它。
  • 实际上,这些在 django 中称为through_tables - 您可以在中间表中存储其他信息。很高兴你喜欢 django - 太棒了!
  • 通读文档,多对多可能仍然是要走的路,但我确实需要 m2m 表上的额外属性。 stackoverflow.com/questions/4443190/… 之类的东西对我有用并稍微简化了查询。非常感谢大家。
【解决方案2】:

您最好先简化模型。我认为您不需要 MembersDivisionTeam 模型:

from django.db import models

class Division(models):
    divname = models.CharField()

class Team(models):
    teamname = models.CharField()
    division = models.ForeignKey(Division)

class Player(models.Model):
    playername = models.CharField()
    team = models.ManyToManyField(Team)

那么,您的查询很简单:

Player.objects.filter(team__division__pk=5)

如果您确实需要每个 cmets 的中间模型,您应该使用 through 关系:

# Uses "Salary" as an example intermediate model.
class Player(models.Model):
    playername = models.CharField()
    team = models.ManyToManyField(Team, through="Salary")

class Salary(models.Model):
    value = models.IntegerField()
    player = models.ForeignKey(Player)
    team = models.ForeignKey(Team)

【讨论】:

  • 我假设 OP 已删除一些字段以使其可读。像“date_started_playing”和“salary”之类的东西会出现在会员模型上,这样玩家就可以成为多个团队的成员。拥有这些中间模型有很多潜在的充分理由。
  • @foobarbecue 好点 - 调整了我的答案以解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2020-07-07
  • 1970-01-01
  • 2020-07-16
  • 2013-05-19
  • 2011-10-09
  • 1970-01-01
相关资源
最近更新 更多