I have a really simple form on which I’m doing some validation:
def clean(self): cleaned_data = super().clean() start = cleaned_data.get("start") end = cleaned_data.get("end") if start >= end: raise ValidationError("start should not be greater than end.")
But I need to add another validation (which is based on the user making the request).
I tried to add the parameter to the clean method:
def clean(self, user): cleaned_data = super().clean() start = cleaned_data.get("start") end = cleaned_data.get("end") if start >= end: raise ValidationError("start should not be greater than end.") if not user.email.endswith("@example.com"): raise ValidationError("blah...")
Unfortunately, I cannot call the is_valid() in the view with a parameter:
if form.is_valid(request.user): ....
I get the following error message:
is_valid() takes 1 positional argument but 2 were given
I also tried to add a new method to the form:
def validate_email(self, user): if not user.email.endswith("@example.com"):: raise ValidationError("blah...")
and call it from the view:
if form.is_valid() and form.validate_email(request.user): obj = form.save(commit=False) obj.created_by = request.user obj.save()
In that case, the exception really gets thrown and crashes the application.
My goals are:
- to make the validation dependant on a criteria in the request
- to display an error message normally when the validation fails
What would be the correct way to implement the custom validation ?
Advertisement
Answer
I would create a simple mixin class
class FormContextMixin: def __init__(self, *args, **kwargs): self.context = kwargs.pop("context", {}) super().__init__(*args, **kwargs)
and then use the FormContextMixin
class with your form class as
class AlbumModelForm(FormContextMixin, forms.ModelForm): def clean(self): user = self.context["request"].user # doe something with `user` class Meta: fields = '__all__' model = Album
Thus, you can initialize the form with any arbitrary data as
form = AlbumModelForm(request.POST, context={"request": request})