1

I would like to raise a ValidationError based on one of the fields in my Django model, without having the respective filed as part of a ModelForm. What I found after googling a bit is the concept of validators for models. So I tried to do the following:

def minimumDuration(value):
    if value == 0:
        raise ValidationError("Minimum value accepted is 1 second!")

class PlaylistItem(models.Model):
    position = models.IntegerField(null=False)
    content = models.ForeignKey(Content, null=True, on_delete=models.SET_NULL)
    item_duration = models.IntegerField(validators = [minimumDuration], default = 5, null=True, blank=True)
    playlist = models.ForeignKey(Playlist, null=True, on_delete=models.CASCADE)

However, no error appears when I introduce 0 in the respective field. From Django's documentation I found out that validators are not automatically applied when saving a model. It redirected me to this page, but I don't really understand how to apply those. Any idea?

Rosi98
  • 107
  • 9
  • so what exactly is unclear, what did you try – iklinac Sep 15 '20 at 11:59
  • there's a type of form called [ModelForm](https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#django.forms.ModelForm) which saves data from a form into the DB table of the model it is bound to. The validation works only when you are working with the forms. – yedpodtrzitko Sep 15 '20 at 12:00

1 Answers1

1

Here is an example of a form with such a custom field outside of the Model:

class ExampleForm(forms.ModelForm):
    custom_field = forms.BooleanField(
        label='Just non model field, replace with the type you need',
        required=False
    )

    class Meta:
        model = YourModel

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # optional: further customize field widget
        self.fields['custom_field'].widget.attrs.update({
            'id': self.instance.pk + '-custom_field',
            'class': 'custom-field-class'
        })
        self.fields['custom_field'].initial = self._get_custom_initial()

    def _get_custom_initial(self):
        # compute initial value based on self.instance and other logic
        return True

    def _valid_custom_field(value):
        # validate your value here
        # return Boolean

    def clean(self):
        """
        The important method: override clean to hook your validation
        """
        super().clean()
        custom_field_val = self.cleaned_data.get('custom_field')
        if not self._valid_custom_field(custom_field_val):
            raise ValidationError(
                'Custom Field is not valid')
dVeza
  • 557
  • 4
  • 12
  • 1
    I needed it the other way around. A field that is NOT in the form, but in the model. I thought that there must be 1-2 lines way of doing that validation, but what I ended up doing was writing my own validation function inside views.py. However, I appreciate your detailed answer and will surely use it if I end up in the reversed situation, haha. Thankies! – Rosi98 Sep 18 '20 at 08:35
  • But why would you not include it in the form and do the validation there :) (similar to model validation) – dVeza Sep 18 '20 at 08:49