Django模型在添加之前验证ManyToMany字段

时间:2018-05-09 19:11:36

标签: django django-models

我有一个看起来像这样的模型:

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


class Flight(models.Model):
    capacity = models.IntegerField()
    passengers = models.ManyToManyField(Passenger)

在将新乘客添加到航班之前,我想验证乘客数量是否不会超过容量。我想知道最好的方法是什么。

显然我可以在添加新乘客之前手动检查乘客数量,但也许在django有一些支持?我尝试编写验证器,但不知道该怎么做。

2 个答案:

答案 0 :(得分:0)

覆盖模型上的clean方法以进行所需的检查:

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

    def clean(self, *args, **kwargs):
        # clean gets called automatically by other things, so we can't always
        # expect flight_id to be provided
        if 'flight_id' in kwargs:
            flight = Flight.objects.get(pk=kwargs['flight_id'])
            if flight.passengers.all().count() >= flight.capacity:
                # flight is full!
                raise ValidationError
        super(Passenger, self).clean()

class Flight(models.Model):
    capacity = models.IntegerField()
    passengers = models.ManyToManyField(Passenger)

请注意,为了做到这一点,您必须在验证乘客时传递航班ID:

f = Flight.objects.get(...)
p = Passenger(name='First', surname='Last')
try:
    p.clean(flight_id=f.id) # full_clean calls clean, among other validations
    p.save()
except ValidationError as e:
    # do something to handle the error

请注意,在多线程应用程序中可以成功验证某些内容,但仍然无法在竞争条件下保存。您需要添加其他代码来处理它。

有关模型验证的详细信息,请参阅here

答案 1 :(得分:0)

根据Django docs,您可以收听 m2m_changed 信号,该信号将触发 pre_add post_add 操作。

  

但是,使用具有多对多关系的add()不会调用   任何save()方法(不存在bulk参数),而是   使用QuerySet.bulk_create()创建关系。如果你需要   建立关系时执行一些自定义逻辑,听   m2m_changed信号,将触发pre_add和post_add   动作。