通过m2m_changed信号处理程序中的模型额外字段访问Django

问题描述 投票:0回答:1

假设我有以下Django模型,它表示父级和子级之间的排序关系:

class Parent(models.Model):
    name = models.CharField(max_length=50)
    children = models.ManyToManyField("Child", through="ParentChild")

class Child(models.Model):
    name = models.CharField(max_length=50)

class ParentChild(models.Model):
    class Meta:
        constraints = [
            models.UniqueConstraint(fields=["parent", "child"], name="uc_parent_child"),
            models.UniqueConstraint(fields=["parent", "sort_number"], name="uc_parent_child"),
        ]

    parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
    child = models.ForeignKey(Child, on_delete=models.CASCADE)
    sort_number = models.IntegerField()

    def save(self, *args, **kwargs):
        exising_sort_numbers = self.parent.parentchild_set.values_list(
            "sort_number", flat=True
        )
        if self.sort_number in exising_sort_numbers:
            raise Exception(f"Duplicate sort number: {self.sort_number}")
        super().save(*args, **kwargs)

现在,如果我使用直通模型创建关系,则会得到重复的sort_number的异常:

ParentChild.objects.create(parent=parent, child=child1, sort_number=0)
ParentChild.objects.create(parent=parent, child=child2, sort_number=0)  # raises Exception

但是,如果我使用.add方法创建关系,则不会出现异常:

parent.children.add(child1, through_defaults={"sort_number": 0})
parent.children.add(child2, through_defaults={"sort_number": 0})  # does NOT raise Exception

我知道using the .add method doesn't call the .save method on the through model,因此我需要使用m2m_change信号来运行此逻辑。但是我不确定如何在此信号中获得sort_number。这是到目前为止我拥有的信号代码:

@receiver(m2m_changed, sender=Parent.children.through)
def validate_something(sender, instance, action, reverse, model, pk_set, **kwargs):
    if action == "pre_add":
        for pk in pk_set:
            child = model.objects.get(pk=pk)
            exising_sort_numbers = instance.parentchild_set.values_list(
                "sort_number", flat=True
            )
            # where's sort_number specified in through_defaults ???

任何想法我如何获得该值并执行"pre_add"验证还是不可能?

django django-models django-signals
1个回答
0
投票
您具有此约束-models.UniqueConstraint(fields=["parent", "sort_number"], name="uc_parent_child"),这意味着您不能将多个具有相同parentsort_number的关系。在ParentChildsave方法中甚至还有一个额外的检查,以进一步强制执行此操作。在尝试创建这种关系时抛出异常是很有意义的。

此外,约束名称必须唯一。我尝试了代码,无法按原样进行迁移。

如果执行您要尝试的操作,则保存时会再次收到该异常。而不是试图破解约束,您应该更改/删除该约束或使您的代码适合于使用该约束-不要尝试创建会违反该约束的实例。

关于您的特定问题,您在validate_something中获得的实例为Parent,并且无法直接访问中间实例,或者它是默认实例。您也无法查询中介实例,因为它尚不存在。

© www.soinside.com 2019 - 2024. All rights reserved.