如何使用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一年了,没有遇到任何问题。