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 = AlbumThus, you can initialize the form with any arbitrary data as
form = AlbumModelForm(request.POST, context={"request": request})