【问题标题】:Forward and reverse query to ManyToMany relation Django对多对多关系 Django 的正向和反向查询
【发布时间】:2018-10-08 13:16:01
【问题描述】:

我有这个模型:

class Task(MPTTModel, TimeStampedModel, StartFinishModel):
    name = models.CharField(max_length=256)
    start_after_end = models.ManyToManyField('self',                                    
                                             related_name='s2e_relation',
                                             blank=True) 
    #s2e means that task can't start before related tasks end

如何获取在此任务结束之前无法开始的所有任务以及必须在此任务开始之前结束的所有任务。

Let's say 1 -> 2 -> 3

我有 id 2。我想找到3 和另一个查询1
要找到 3,我可以使用 Task.objects.get(id = 2).start_after_end.all()
我怎样才能找到1

更新 1
实际上找出更大的问题 - 如果我选择 2 related to 1 - 1 立即更改与 1 is related to 2 的关系

【问题讨论】:

  • 你需要使关系不对称。
  • @Willem Van Onsem 你是什么意思?

标签: python django


【解决方案1】:

如果你与'self' 建立关系,默认情况下 Django 将建立关系对称。这意味着如果一个对象a 拥有朋友b,那么b 自动拥有朋友a。所以这意味着这里的关系看起来像:

# symmetrical relation
1  <---> 2 <---> 3

因此意味着:

task1.start_after_end.all()  # ==> [2]
task2.start_after_end.all()  # ==> [1, 3]
task3.start_after_end.all()  # ==> [2]

所以这里13 都将被视为Task2.start_after_end.all()s。您可能想要:您希望关系是非对称的

所以您应该将字段编辑为:

class Task(MPTTModel, TimeStampedModel, StartFinishModel):
    name = models.CharField(max_length=256)
    start_after_end = models.ManyToManyField(
        'self',                                    
        related_name='s2e_relation',
        symmetrical=False,
        blank=True
    )

现在上面看起来像:

# asymmetrical relation
1   ---> 2  ---> 3

请注意,非对称关系是反对称关系。仍然可以将task1 添加到task2start_after_end,但是如果您将task2 添加到task1start_after_end,它不会自动执行此操作。

所以现在如果完成了,这意味着对于some_task,我们将获得下一个任务:

my_task.start_after_end.all()  # the next ones

我们用related_name 得到之前的那些:

my_task.s2e_relation.all()     # the previous ones

例如:

task1 = Task.objects.create(name='task1')
task2 = Task.objects.create(name='task2')
task3 = Task.objects.create(name='task3')

task1.start_after_end.add(task2)
task2.start_after_end.add(task3)

然后如果我们触发关系,我们得到:

task1.start_after_end.all()  # ==> [2]
task2.start_after_end.all()  # ==> [3]
task3.start_after_end.all()  # ==> []

task1.s2e_relation.all()  # ==> []
task2.s2e_relation.all()  # ==> [1]
task3.s2e_relation.all()  # ==> [2]

【讨论】:

  • 哇,一如既往的好答案!感谢您的帮助,我现在将对其进行测试,但我觉得应该可以:)
  • @Chiefir:请注意,如果您已经添加了数据,这可能会导致一些问题,因此您可能需要修复现有数据。
  • 是的,我猜 flushloaddata 会有所帮助:)
【解决方案2】:

想法是使用related_name='s2e_relation'传入ManyToManyField

您可以这样做:

Task.objects.get(id=2).s2e_relation.all()

【讨论】:

  • 是的,关系应该是asymmetrical,然后这应该可以工作。
猜你喜欢
  • 2019-05-18
  • 1970-01-01
  • 2016-09-15
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
相关资源
最近更新 更多