Home > Software design >  Django file upload with model form
Django file upload with model form

Time:11-22

there are tons of relevant posts:

I am creating a simple app that allow user to upload css file:

First, validate field field to make sure the file is css and the max size does not exceed 5MB.

fields.py

from django.db import models
from django import forms
from django.template.defaultfilters import filesizeformat


def mb(n):
    return n * 1048576


class FileField(models.FileField):
    def __init__(self, *args, **kwargs):
        self.content_types = kwargs.pop('content_types', [])
        self.max_upload_size = kwargs.pop('max_upload_size', [])
        super().__init__(*args, **kwargs)
    
    def clean(self, *args, **kwargs):
        data = super().clean(*args, **kwargs)
        file = data.file

        try:
            content_type = file.content_type
            if content_type in self.content_types:
                if file.size > self.max_upload_size:
                    raise forms.ValidationError('Please keep filesize under {}. Current filesize {}'
                    .format(filesizeformat(self.max_upload_size), filesizeformat(file.size)))
            else:
                raise forms.ValidationError('File type rejected')
        except AttributeError:
            pass
        return data

second, implement validation into model

models.py

# Create your models here.
class Css(models.Model):
    file = FileField(
        upload_to='css', 
        content_types=['text/css'],
        max_upload_size=mb(5),
    )

third, create form for model creation

forms.py

class CssCreateForm(forms.ModelForm):
    class Meta:
        model = Css
        fields = ['file']

last, write a callable view

views.py

# Create your views here.
def cssUploadView(request):
    if request.method == 'POST':
        print(request.POST['file'])
        print(type(request.POST['file']))
        print(request.FILES)
        form = forms.CssCreateForm(request.POST, request.FILES)
        if form.is_valid():
            print('---------')
            print(form.cleaned_data['file'])
        else:
            print('not valid')
    else:
        form = forms.CssCreateForm()
        return render(request, 'css/css_create.html', {
            'form': form,
        })

template

<form method="POST">
    {% csrf_token %}
    <div class="form-title">Upload a new CSS file</div>
    {{ form.as_p }}
    <div class="button-area">
        <button id="go" type="submit">Go</button>
    </div>
</form>

The expected result is that

  • when uploading html file, or css file larger than 5MB, ValidationError will be raised

However, in view

  • Both request.FILES and form.cleaned_data['file'] fails to retrieve uploaded file.
  • form.is_valid always returns True

for example, when I upload clean.py:

clean.py
<class 'str'>
<MultiValueDict: {}>
---------
None

I wonder why file fails to upload and validation does not work. Any suggestion will be appreciated.

CodePudding user response:

You have to specify the data encoding method in your html form.

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <div class="form-title">Upload a new CSS file</div>
    {{ form.as_p }}
    <div class="button-area">
        <button id="go" type="submit">Go</button>
    </div>
</form>
  • Related