2010-03-21 81 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消息顯示,作爲用戶的反饋。

相關問題