Limit Maximum Choices of ManyToManyField

后端 未结 3 1421
清酒与你
清酒与你 2021-02-20 16:51

I\'m trying to limit the maximum amount of choices a model record can have in a ManyToManyField.

In this example there is a BlogSite that can be related to Regions. In t

相关标签:
3条回答
  • 2021-02-20 17:34

    You can override clean method on your BlogSite model

    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
    

    And if you use django's ModelForm then this error will appear in form's non_field_errors.

    EDIT:

    M2m fields are saved after the model is saved, so the code above will not work, the correct way you can use m2m_changed signal:

    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)
    

    Give it a try it worked for me.

    0 讨论(0)
  • 2021-02-20 17:41

    Working! I have used this and its working properly. Validation required before saving the data. So you can use code in form

    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__'
    
    0 讨论(0)
  • 2021-02-20 17:45

    The best that I can think of is to have a pre-save signal for BlogSite and check whether this instance of BlogSite has already had 3 regions.

    @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")
    
    0 讨论(0)
提交回复
热议问题