Search code examples
djangoformsfilefield

Django validate FileField with clean()


I have a Form that includes a FileField and a CharField. Both work as expected.

Neither field is required by itself, but one of them has to be given. So I want to add a validation that fails if both are empty.

in forms.py:

class MyForm(forms.Form):
    mytext = forms.CharField(
        label = "Enter text",
        required=False
        )
    myfile = forms.FileField(
        label = "Or upload file",
        required=False
        )

    def clean(self):
        super(MyForm, self).clean()

        mytext_value = self.cleaned_data.get("mytext")
        myfile_value = self.cleaned_data.get("myfile")  # this remains empty, even after selecting a file! :-(

        if not mytext_value and not myfile_value:
            self.add_error("mytext", "Either text or file must be given!")

        return self.cleaned_data

This validation fails even if a file has been uploaded! (It does not fail if the text field has been used.)

If I disable the validation, the form works fine within the app. In views.py, I can get the uploaded file from the request (myfile_value = request.FILES.get("myfile")) and work with it.

But how do I get the content of the file during the clean() call, where I do not have a request, yet?

self.files gives me an empty MultiValueDict, self.data doesn't contain the key myfile at all, and in self.cleaned_data, myfile is None.

How can I check during form validation whether a FileField has been filled?


Solution

  • The problem was not the form, but the associated view:

    Wrong forms.py:

    if request.method == "POST":
        form = MyForm(request.POST)
        if form.is_valid():
            mytext = request.POST.get("mytext")
            myfile = request.FILES.get("myfile")   
    

    I didn't pass request.FILES to the form, so no wonder the validation didn't find it. While below this point, I retrieved the file directly from the request and was fine.

    Right forms.py:

    if request.method == "POST":
        form = MyForm(request.POST, request.FILES)
        if form.is_valid():
            mytext = form.cleaned_data.get("mytext")
            myfile = form.cleaned_data.get("myfile")