如何使用Django ORM进行这种特殊的多字段验证?

如何使用Django ORM进行这种特殊的多字段验证?,django,validation,many-to-many,Django,Validation,Many To Many,我有以下模型: class Step(models.Model): order = models.IntegerField() latitude = models.FloatField() longitude = models.FloatField() date = DateField(blank=True, null=True) class Journey(models.Model): boat = models.ForeignKey(Boat)

我有以下模型:

class Step(models.Model):

    order = models.IntegerField()
    latitude = models.FloatField()
    longitude = models.FloatField()
    date = DateField(blank=True, null=True)


class Journey(models.Model):

    boat = models.ForeignKey(Boat)
    route = models.ManyToManyField(Step)
    departure = models.ForeignKey(Step, related_name="departure_of", null=True)
    arrival = models.ForeignKey(Step, related_name="arrival_of", null=True)
我想执行以下检查:

        # If a there is less than one step, raises ValidationError.

        routes = tuple(self.route.order_by("date"))

        if len(routes) <= 1:
            raise ValidationError("There must be at least two setps in the route")

        # save the first and the last step as departure and arrival
        self.departure = routes[0]
        self.arrival = routes[-1]

        # departure and arrival must at least have a date
        if not (self.departure.date or self.arrival.date):
            raise ValidationError("There must be an departure and an arrival date. "
                                  "Please set the date field for the first and last Step of the Journey")

        # departure must occurs before arrival    
        if not (self.departure.date > self.arrival.date):
            raise ValidationError("Departure must take place the same day or any date before arrival. "
                                  "Please set accordingly the date field for the first and last Step of the Journey")

我试图通过重载save来实现这一点。不幸的是,save中的travely.route为空。而且,travely.id还不存在。我没有尝试django.db.models.signals.post_save,但假设它会失败,因为travely.route也是空的,它什么时候会被填满?。我在django.db.models.signals.m2m_中看到了一个解决方案,但是有很多步骤需要修改,我希望避免对每一个步骤都执行操作。

如果您运行的是最新和最棒的django,请看一下这个


基本上,可以用与表单相同的方式验证模型。虽然我自己从未使用过它,但它看起来非常适合您正在尝试的操作。

最终,我不得不为创建此对象的每个表单编写验证。knutin的解决方案会很好,但我运行Django1.1

总之,Django让您很容易地重载管理验证,因此我做到了:

class JourneyAdminForm(forms.ModelForm):

    class Meta:
        model = Journey

    def clean_route(self):
        """
            Ensure a Journey includes at least 2 dated steps, 
            departure starting before arrival.
        """

        # must use getlist as self.data is not a dict but a querydict
        routes = self.data.getlist("route")

        if len(routes) <= 1:
            raise ValidationError("There must be at least two setps in the route")

        departure = Step.objects.get(id=routes[0])
        arrival = Step.objects.get(id=routes[-1])
        self.data["departure"] = departure.id
        self.data["arrival"] = arrival.id


        if not (departure.date and arrival.date):
            raise ValidationError("There must be an departure and an arrival date. "
                                  "Please set the date field for the first and last Step of the Journey")

        if not (departure.date <= arrival.date):
            raise ValidationError("Departure must take place the same day or any date before arrival. "
                                  "Please set accordingly the date field for the first and last Step of the Journey")

        return self.cleaned_data["route"]

class JourneyAdmin(admin.ModelAdmin):

    exclude = ("arrival", "departure")
    form = JourneyAdminForm

admin.site.register(Journey, JourneyAdmin)

另外,在提交表单时,ValidationError消息会显示为用户的反馈。

很好,但不幸的是,我不相信生产代码的不稳定版本。我的bug已经够多了:-顺便说一句,目前主干代码与1.2版本完全相同,加上一些bug需要在实际发布之前修复。我们已经在一个生产应用程序中跟踪trunk一年了,没有遇到任何问题。