shashank
shashank

Reputation: 3

Django UpdateView and ModelForm for file upload is not working

issue

Whenever I am trying to submit form without uploading a new file, I am getting error due to form clean method. How will one submit update form with same file. error - AttributeError: 'FieldFile' object has no attribute 'content_type'

views.py

class DocUpdate(UpdateView):
        model = Document
        form_class = CreateDocForm
        template_name = 'mydoc/doc_update.html'
        success_url = reverse_lazy('mydoc:doc_list')
        context_object_name = 'document'

        def get_form_kwargs(self):
            kwargs = super(DocUpdate, self).get_form_kwargs()
            kwargs['request'] = self.request
            return kwargs

forms.py

class CreateDocForm(forms.ModelForm):
file = forms.FileField(label='Select a file', help_text='only img/jpg/jpeg, pdf, doc/docx, xls/xlsx files are '
                                                        'allowed with max. 50  megabytes size.')

def __init__(self, *args, **kwargs):
    self.extension = ''
    self.size = ''
    self.password = ''
    self.name = ''
    self.request = kwargs.pop("request")
    super(CreateDocForm, self).__init__(*args, **kwargs)

class Meta:
    model = Document
    fields = ['file', 'description']

def clean(self):
    # validate mime type of file
    file = self.cleaned_data['file']
    self.name, self.extension = os.path.splitext(file.name)
    if self.extension not in settings.VALID_FILE_EXTENSIONS:
        raise forms.ValidationError("Invalid file extension.")
    mime = file.content_type
    self.size = int(file.size)
    if mime not in settings.VALID_FILE_MIME_TYPES:
        raise forms.ValidationError("Invalid file content.")
    if self.size > settings.MAX_UPLOAD_SIZE:
        raise forms.ValidationError("File size exceeded.")

    return self.cleaned_data

def save(self, *args, **kwargs):
    self.instance.extension = self.extension
    self.instance.size = self.size
    self.instance.password = self.password
    self.instance.user = self.request.user
    file_instance = super(CreateDocForm, self).save(*args, **kwargs)
    return file_instance

doc_update.html

<form id="createDocForm" method="post" enctype="multipart/form-data">
                {% csrf_token %}
                {{ form|crispy }}
                <button class="btn btn-primary" type="submit">Update</button>
                <a class="btn btn-primary" href="{% url 'mydoc:doc_list' %}">Back</a>
            </form>

traceback

Traceback (most recent call last):
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/views/generic/base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/views/generic/base.py", line 97, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/views/generic/edit.py", line 194, in post
    return super().post(request, *args, **kwargs)
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/views/generic/edit.py", line 141, in post
    if form.is_valid():
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/forms/forms.py", line 185, in is_valid
    return self.is_bound and not self.errors
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/forms/forms.py", line 180, in errors
    self.full_clean()
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/forms/forms.py", line 382, in full_clean
    self._clean_form()
  File "/home/user/projects/django/mysite/mysite_venv/lib/python3.6/site-packages/django/forms/forms.py", line 409, in _clean_form
    cleaned_data = self.clean()
  File "/home/user/projects/django/mysite/djangoapp/mydoc/forms.py", line 30, in clean
    mime = file.content_type
AttributeError: 'FieldFile' object has no attribute 'content_type'

Upvotes: 0

Views: 630

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599630

There does appear to be an inconsistency in the way files are represented in a ModelForm depending on whether they are updated in the submitted data or not. So I guess the only thing to do is to add a condition that checks for that:

from django.core.files.uploadedfile import UploadedFile
...
def clean(self):
    file = self.cleaned_data['file']
    if isinstance(file, UploadedFile):
        ...

Note by the way that this code only deals with the file field, so should really be in the clean_file method not the generic clean.

Upvotes: 1

Related Questions