【问题标题】:Update the reverse Foreign key Model on Model update在模型更新时更新反向外键模型
【发布时间】:2017-12-11 08:11:21
【问题描述】:

我有 3 个模型,帐户、公司和产品。产品有一个外键到公司、公司和外键帐户。 它们都有一个名为“is_active”的字段。

class Product(Meta):
    company = models.ForeignKey(Company, related_name='products', on_delete=models.CASCADE)
    is_active = models.BooleanField(default=False)


class Company(Meta):
    account = models.ForeignKey(Account, related_name='account', on_delete=models.CASCADE)
    is_active = models.BooleanField(default=False)  

我需要什么:

  1. 当公司 is_active 变为 False 我希望所有与公司相关的产品时,is_active 变为 false
  2. 当 Account is_active 变为 False 我希望所有与该帐户相关的公司,is_active 变为 false,并传播到产品

我知道我需要更改保存(或使用保存后信号),但我不知道如何选择和更改外键模型,并向下传播多个级别,以防帐户

父子之间的关系是反向的,而不是子父子之间的关系。,所以没有可用的字段 FK。

【问题讨论】:

  • 反向关系的实例可通过MODEL_set 访问,例如对于 Company 实例,您可以通过 company_instance.product_set 访问其所有产品。这回答了你的问题了吗? docs.djangoproject.com/en/2.0/topics/db/queries/…
  • @petr 我可以使用相关名称,而不是默认名称,但作为反向 FK,我需要遍历它们并在子模型上进行保存/更新,以防帐户传播进一步,我尝试了一些东西,但它们不起作用;也许你可以给我一个完整问题的例子
  • 您不需要更进一步 - 两个模型都将覆盖 save() 方法,这意味着当您将实例更改为一个关系时,其他模型将自动传播。

标签: django django-models


【解决方案1】:

让我告诉你我的解决方案。首先,您应该跟踪字段的更改(在本例中为“is_active”)。要在模型的 init 中执行此操作,必须保留缓存值并在保存时检查值:如果更改,则更新数据库:

class Company(Meta):
   ...(field definitions)

   def __init__(self, *a, **kw):
       super().__init__(*a, **kw):
       self.__original_is_active = self.is_active

   def save(self, *a, **kw):
      if self.__original_is_active != self.is_active and self.is_active==False:
          # use raw update to perform better than loop
          self.products.update(is_active=False)
      super().save(*a, **kw)

更新(添加帐户更改代码) 我想公司模型与 Account 有 ForeignKey 关系

class Account(Meta):
    ...(field definitions)

    def __init__(self, *a, **kw):
        super().__init__(self, *a, **kw)
        self.__original_is_active = self.is_active

    def save(self, *a, **kw):
        if self.__original_is_active != self.is_active and self.is_active == False:
            for company in self.company_set.all():
                company.is_active = False
                company.save()
        super().save(*a, **kw)

如果您的帐户与公司之间存在多对多关系,则在保存方法中将 self.company_set.all() 更改为 self.companies.all() 即可。

你的 Account 模型也会有类似的变化,但不要忘记使用 for 循环更新公司,因为“update”方法不会生效,因为它会直接执行 SQL 而忽略了“init,保存”我在公司所做的事情(就像docs 说的那样)

【讨论】:

  • 谢谢,所以你是说在Account的情况下,而不是使用“self.companies.update(is_active=False)”来使用for循环;如果在某些情况下只有一家公司会更新工作怎么办?
  • 不使用update()方法,不会调用外键相关对象的save方法。请查看说明相同的文档 (docs.djangoproject.com/en/2.0/topics/db/queries/…)。所以不管你有多少外键相关的对象,你必须使用for循环(也更新了我的答案)
  • 能否请您也添加for循环的示例,我尝试了一些但没有按预期工作
猜你喜欢
  • 2021-08-27
  • 2020-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 2019-07-17
  • 1970-01-01
  • 2018-06-30
相关资源
最近更新 更多