在 Django 中保存包含 FileField 的模型

Saving a model containing a FileField in Django

我有以下型号;

class AudioFile(models.Model):
    name = models.CharField(max_length=100, default='')
    audio_file = models.FileField()
    uploader = models.ForeignKey(User, default='')

    def __unicode__(self):
        return self.name    

下表;

class AudioFileForm(forms.ModelForm):
    class Meta:
        model = AudioFile
        fields = ['name', 'audio_file']

    def clean_audio_file(self):
        audio = self.cleaned_data.get('audio_file',False)
        if audio:
            if audio._size > 5*1024*1024:
                raise ValidationError("File too large ( > 5mb )")
            if os.path.splitext(audio.name)[1] != ".mp3":
                raise ValidationError("We only support mp3!")
            return audio
        else:
            raise validationError("Couldn't read uploaded file")

如您所见,有一些自定义验证

然后我将下面的 html 与 AudioFileForm 作为 form;

传递
<!DOCTYPE html>
<html>
<head>
</head>

<body>
  <form method="post" action="{% url 'actual_upload_audio' %}">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Upload"/>
  </form>
</body>
</html>

现在我知道如果对象不包含 FileField 如何保存它。我会做这样的事情;

form = AudioFileForm(request.POST)
if form.is_valid():
    name = form.cleaned_data['name']
    //Say it contained another field, foo
    foo = form.cleaned_data['foo'] 
    uploader = request.user //view requires login
    audio_file = Audio_File.objects.create(name=name,
                                           foo=foo,
                                           uploader=uploader)
    audio_file.save()
    return HttpResponse("Success!")

但是有一个 FileField 有问题我不知道如何处理它。我阅读了 Django 的文档,但并没有真正理解它。一个更简单详细的解释会很可爱。

首先,我的 settings.py

中有 MEDIA_ROOT = '/home/afzalsh/works/openradio/audio_files/'

更新

感谢@Rohan,我现在有 <form method="post" action="{% url 'actual_upload_audio' %}" enctype="multipart/form-data"> 而不是 <form method="post" action="{% url 'actual_upload_audio' %}">

感谢@dzejdzej,还有以下视图;

form = AudioFileForm(request.POST, request.FILES)
    if form.is_valid():
        form.cleaned_data['uploader'] = request.user
        form.save()
        return HttpResponseRedirect(reverse('home_audio',kwargs={'pk':audio_file.pk}))
    else:
        return HttpResponse("Form Invalid!")

但是Form Invalid!:/

您的表单应具有 enctype="multipart/form-data" 属性,以便提交文件。

<form method="post" action="{% url 'actual_upload_audio' %}"
       enctype="multipart/form-data" >
   ...
 </form>

您应该提及 upload_to 属性:audio_file = models.FileField(upload_to='uploads')

此处 'uploads' 是您要将文件上传到的目录的名称。

既然您使用的是 ModelForm,为什么不让 Django 处理保存整个模型?

from django.shortcuts import redirect

form = AudioFileForm(request.POST)
if form.is_valid():
    form.cleaned_data['uploader'] = request.user //view requires login
    form.save()
    return redirect(success_url)

如果您使用的是 Django >=1.7,则不再需要 upload_to 字段。但是,我认为这是一个很好的做法。 https://docs.djangoproject.com/en/1.8/ref/models/fields/#django.db.models.FileField.upload_to

成功后也重定向用户 POST 以避免 csrf 问题。

作为Rohan seaid,您必须像这样在模板中污染您的表格。

<form method="post" action="{% url 'actual_upload_audio' %}"
       enctype="multipart/form-data" >
   ...
</form>

这允许您将请求的文件发送到 view。现在看来你一定有这样的东西:

def my_view(request):
    if request.method == 'POST':
        my_form = MyForm(request.POST, request.FILES)
        if my_form.is_valid():
            my_form.save()

您可以使用 request.FILES

初始化表单 FileField 和 ImageField