2013-11-25 10 views
7

モデルレコードがManyToManyFieldに持つことのできる最大量を制限しようとしています。ManyToManyFieldの上限の選択

この例では、地域に関連付けることができるBlogSiteがあります。この例では、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に表示されます。

EDIT:

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) 

は、それが働いた試してみてください:保存されている上記のコードは動作しませんので

M2Mフィールドは、モデルの後にあなたがm2m_changed信号を使用することができます正しい方法を保存しています私のために。

+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

この回答は間違っています。 'pre_save'はm2mのセーブがまだ発生していないときに起動されるので、カウントは変更前の値を返します。 – andi