限制ManyToManyField的最大选择

时间:2013-11-25 21:33:57

标签: django django-models

我正在尝试限制模型记录在ManyToManyField中可以选择的最大数量。

在此示例中,有一个可以与Regions相关的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)
    ....

有什么想法吗?

3 个答案:

答案 0 :(得分:10)

您可以在clean型号

上覆盖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

如果你使用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)

尝试一下它对我有用。

答案 1 :(得分:2)

工作!我已经使用了它,并且工作正常。 保存数据之前需要验证。所以您可以使用表单中的代码

class BlogSiteForm(forms.ModelForm):
    def clean_regions(self):
        regions = self.cleaned_data['regions']
        if len(regions) > 3:
            raise forms.ValidationError('You can add maximum 3 regions')
        return regions
    class Meta:
        model = BlogSite
        fields = '__all__'

答案 2 :(得分: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")