【问题标题】:ManyToMany field constraints in DjangoDjango中的ManyToMany字段约束
【发布时间】:2019-10-08 20:22:18
【问题描述】:

这是一个通用的数据库问题,并非特定于 Django。由于我使用的是 Django,所以我在这种情况下问它。假设我有三个模型:

class ModelA(models.Model)
    name = models.CharField(max_length=255)

class ModelB(models.Model)
    a = models.ForeignKey(ModelA, on_delete=models.CASCADE)

class ModelC(models.Model)
    a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
    bs = models.ManyToManyField(ModelB, blank=True)

我希望ModelC 拥有指向许多ModelBs 的链接。我希望有一个约束,只允许ModelC 有一个ModelB,如果他们共享一个共同的ModelA。有没有办法在数据库级别正确地构建它,或者应该在系统的其他部分逻辑地完成这个?

【问题讨论】:

    标签: django database django-models


    【解决方案1】:

    我认为没有办法在数据库级别强制执行,但要在应用程序代码中强制执行,您可以使用m2m_changed 信号 (https://docs.djangoproject.com/en/2.2/ref/signals/#m2m-changed) 以便在添加任何内容之前进行此检查你的多对多关系。

    【讨论】:

    • 如果您需要任何说明,请告诉我!
    【解决方案2】:

    感谢Ross Mechanic,我用那个方法解决了这个问题。对于其他有相同问题的人,我用以下方法解决了它:

    def bs_changed(**kwargs):
        """
        :param kwargs:
        :return:
        """
        if kwargs['action'] != 'pre_add':
            return
    
        if kwargs['reverse']:
            b = kwargs['instance']
            cs = kwargs['model'].objects.filter(id__in=kwargs['pk_set'])
            for c in cs:
                if b.a != c.a:
                    kwargs['pk_set'].remove(c.id)
        else:
            c = kwargs['instance']
            bs = kwargs['model'].objects.filter(id__in=kwargs['pk_set'])
            for b in bs:
                if b.a != c.a:
                    kwargs['pk_set'].remove(b.id)
    
    
    m2m_changed.connect(bs_changed, sender=ModelC.members.through)
    

    【讨论】:

      【解决方案3】:

      除了Ross Mechanic的回答,我建议给m2m_changed给出的动作添加一个条件。否则,您将在 django 管理页面中尝试更改它时出错。 喜欢

      @receiver(m2m_changed, sender=ModelC.bs.through)
      def constraints_on_bs(sender, **kwargs):
          action = kwargs.get('action', None)
          if 'post' in action and error:
              raise ValidationError('Error with the relation m2m')
      

      【讨论】:

        猜你喜欢
        • 2015-10-25
        • 2019-11-01
        • 2023-02-13
        • 1970-01-01
        • 2011-04-26
        • 2020-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多