Допустим, у меня есть следующие 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
Я знаю использование метода .add не вызывает метод .save на сквозной модели , поэтому мне нужно использовать сигнал m2m_change
для запуска этой логики c. Но я не уверен, как получить 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"
, или это невозможно?