限制ManyToManyField的最大选择

aww*_*ter 9 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)
    ....
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Mou*_*nir 12

您可以覆盖模型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
Run Code Online (Sandbox Code Playgroud)

如果你使用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)
Run Code Online (Sandbox Code Playgroud)

尝试一下它对我有用.


Nid*_*wal 5

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

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__'
Run Code Online (Sandbox Code Playgroud)