2013-11-25 23 views
7

我試圖限制模型記錄在ManyToManyField中可以有的最大選擇量。限制ManyToManyField的最大選擇

在這個例子中有一個BlogSite可以和Regions有關。在這個例子中,我想限制BlogSite只能有3個區域。

這似乎是以前會被問到/回答的事情,但是在幾個小時的探頭周圍找不到任何接近的東西。對於這個項目,我使用的是Django 1.3。

#models.py 
class BlogSite(models.Model): 
    blog_owner = models.ForeignKey(User) 
    site_name = models.CharField(max_length=300) 
    region = models.ManyToManyField('Region', blank=True, null=True) 
    .... 

class Region(models.Model): 
    value = models.CharField(max_length=50) 
    display_value = models.CharField(max_length=60) 
    .... 

任何想法?

回答

10

您可以在BlogSite模型

from django.core.exceptions import ValidationError 

class BlogSite(models.Model): 

    blog_owner = models.ForeignKey(User) 
    site_name = models.CharField(max_length=300) 
    regions = models.ManyToManyField('Region', blank=True, null=True) 

    def clean(self, *args, **kwargs): 
     if self.regions.count() > 3: 
      raise ValidationError("You can't assign more than three regions") 
     super(BlogSite, self).clean(*args, **kwargs) 
     #This will not work cause m2m fields are saved after the model is saved 

覆蓋clean方法,如果你使用Django的ModelForm然後將出現在窗體的non_field_errors此錯誤。

編輯:保存模型後

M2M領域都省了,所以上面的代碼將無法正常工作,您可以使用m2m_changed信號的正確方法:

from django.db.models.signals import m2m_changed 
from django.core.exceptions import ValidationError 


def regions_changed(sender, **kwargs): 
    if kwargs['instance'].regions.count() > 3: 
     raise ValidationError("You can't assign more than three regions") 


m2m_changed.connect(regions_changed, sender=BlogSite.regions.through) 

試試看它的工作爲了我。

+0

這非常接近。出於某種原因,這使得我可以保存3個以上的區域,但是當我嘗試並保存後再糾正到2時,它會給我帶來錯誤。從這裏工作的解決方案,謝謝... – awwester

+0

我更新了我的迴應。編輯作品 – Mounir

+0

。很高興知道m2m的清潔差異,謝謝! – awwester

0

我能想到的最好的方法是爲BlogSite預先保存一個信號並檢查BlogSite的這個實例是否已經有3個區域。

@receiver(pre_save, sender=BlogSite) 
def check_regions_limit(sender, instance, **kwargs): 
    if instance.regions.count() == 3: 
     raise_some_exception("Can't add more than 3 regions to a BlogSite") 
+2

這個答案是錯誤的。當m2m保存還沒有發生時''pre_save'被觸發,所以計數會在更改前返回值。 – andi