开发者

Django file upload: filename not sticking

I'm uploading files and storing metadata in a db. Part of the metadata is the file name itself. However, somewhere down the line, the filename seems to not be getting saved! I will paste only what I think are relevant parts of the code to keep this short.

class UploadFile(models.Model):
   ...
    theFile = models.FileField(upload_to = "Genius/Uploads/", null = True)
    filename = models.CharField(max_length = 50, blank = True, null = False)

class UploadFileForm(ModelForm):
    class Meta:
        model = UploadFile
        fields = ('title', 'theFile', 'date_uploaded',) # Don't prompt for filename


def files_upload(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)开发者_如何转开发
        if form.is_valid():
            form.filename = request.FILES['theFile'].name # TODO: sanitize!
            # form.filename = 'foo'
            form.save()
            return HttpResponseRedirect('/files/upload/successful/')
        else:
            form = UploadFileForm()
        return render_to_response('files/upload_file.html', { 'form': form })

I have checked the value of request.FILES['theFile'].name before & after saving the form. For whatever reason it is intact but never seems to make it into the DB.


That's because form.filename is the form field, not the value it will be saving.

You are looking for something like this:

class UploadFileForm(ModelForm):
    def save(self, commit=True):
        instance = ModelForm.save(self, commit=False)
        instance.filename = self.files['theFile'].name

        if commit:
            instance.save()

        return instance

    class Meta:
        model = UploadFile
        fields = ('title', 'theFile', 'date_uploaded',) # Don't prompt for filename

Alternative solution:

upload_file = form.save(commit=False)
upload_file.filename = request.FILES['theFile'].name
upload_file.save()


Form field values aren't accessed via attributes on the form. So setting 'form.filename' doesn't set the value to be saved in the filename field. Instead, set the value on the instance returned by form.save().

upload_file = form.save(commit=False) 
upload_file.filename = filename
upload_file.save() 


I just wanted to add that, in the future, you might try to avoid putting such business logic on the model form. While WoLpH's answer is correct and a great example of how to handle additional model instance processing through ModelForm, particular cases of having fields dependent on other fields data is handled in the Model, Form and ModelForm API through their respected clean() methods and is mentioned in several places in the official reference docs (here's one on forms, though the same holds true for the Model and ModelForm APIs).

In your case this would mean:

import os

class UploadFile(models.Model):

     # ...

     def clean(self):
          # Field data has already been populated by this point.
          # Note that `FieldFile` inherits from `File` and that
          # `File.name` is actually the full path to the file
          # so we need to get the base path component sans the extension

          path, extension = os.path.splitext(self.thefile.file.name)
          self.filename = os.path.basename(path)

And that's about it! If you properly set the editable attribute on your model fields, you'll find that you can rely on Django to automatically generate the ModelForm for the UploadFile model. That means you don't have to define a ModelForm for the generic create, update views or your model's ModelAdmin and that's less lines of code to manage!

The general rule of thumb is that you think twice about whether overriding default behavior is ever justified or self-contained, especially when your working at the far end of the business logic chain, otherwise you may feel the wrath of unexpected flops.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜