2010-03-21 50 views
1

我有如下因素模型:如何使用Django ORM进行特殊的many2many字段验证?

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()中为空。更何况,Journey.id还不存在。我没有尝试django.db.models.signals.post_save,但假设它会失败,因为Journey.route也是空的(无论如何,这是否填充?)。我在django.db.models.signals.m2m_changed中看到了一个解决方案,但是有很多步骤(数千),并且我希望避免为它们中的每一个执行操作。

回答

0

如果你正在运行的是最新和最伟大的Django,看看这个http://docs.djangoproject.com/en/dev/ref/models/instances/#id1

基本上,它是可以验证模型以同样的方式为形式。虽然我从来没有用过它,但它看起来很适合你想要做的事情。

+0

良好的捕获,但不幸的是我不相信生产代码的不稳定版本。我的脚本已经足够了:-) – 2010-03-21 20:22:10

+0

作为一个附注,目前主干与1.2版本的代码完全相同,并且在实际发布之前需要修复一些错误。 我们一直在生产应用程序中追踪树干一年,并且没有任何问题。 – knutin 2010-03-22 10:21:51

0

最后,我不得不为每个创建此对象的表单写一个验证。 knutin的解决方案本来很好,但我运行Django 1.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消息显示,作为用户的反馈。

相关问题