{"title":"文件上传","version":"2.2","locale":"zh-hans","docname":"topics/http/file-uploads","url":"/zh-hans/2.2/topics/http/file-uploads/","canonical":"https://djangodocs.dev/zh-hans/2.2/topics/http/file-uploads/","summary":"Django处理文件上传时, 文件最终会位于:attr:request.FILES <django.http.HttpRequest.FILES> (想了解更多关于``request`` 对象的信息请阅读 request and response…","html":"<h1>文件上传<a class=\"heading-anchor\" href=\"#file-uploads\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django处理文件上传时, 文件最终会位于:attr:request.FILES &lt;django.http.HttpRequest.FILES&gt; (想了解更多关于``request`` 对象的信息请阅读  <span class=\"xref std std-doc\">request and response objects 1</span>) 。本文档主要介绍文件是如何存储在硬盘和内存中的，以及如何定制默认行为。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>如果接收不受信任的用户的上传会有安全隐患， 请阅读 :ref:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>user-uploaded-content-security`获取详情.</p>\n</aside>\n<section id=\"basic-file-uploads\">\n<h2>简单文件上传<a class=\"heading-anchor\" href=\"#basic-file-uploads\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>考虑使用一个简单的表单，表单中包含一个:class:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>~django.forms.FileField`字段:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">forms.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django</span> <span class=\"kn\">import</span> forms\n\n<span class=\"k\">class</span> <span class=\"nc\">UploadFileForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>Form<span class=\"p\">):</span>\n    title <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n    file <span class=\"o\">=</span> forms<span class=\"o\">.</span>FileField<span class=\"p\">()</span>\n</code></pre></figure>\n<p>处理这个表单的视图将通过:attr:request.FILES &lt;django.http.HttpRequest.FILES&gt;`获取到文件数据, attr:`request.FILES &lt;django.http.HttpRequest.FILES&gt;`是包含了表单中每个 :class:`~django.forms.FileField (还有 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/forms/fields/#django.forms.ImageField\" title=\"django.forms.ImageField\"><code class=\"xref py py-class docutils literal notranslate\">ImageField</code></a>, 以及其他:class:~django.forms.FileField 的子类)键值的字典 。所以 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>数据可以通过`request.FILES['file']``获取到。</p>\n<p>请注意只有在请求是通过 <code class=\"docutils literal notranslate\">POST</code> 提交且提交的  <code class=\"docutils literal notranslate\">&lt;form&gt;</code> 表单有 <code class=\"docutils literal notranslate\">enctype=&quot;multipart/form-data&quot;</code> 属性的时候，<a class=\"reference internal\" href=\"/zh-hans/2.2/ref/request-response/#django.http.HttpRequest.FILES\" title=\"django.http.HttpRequest.FILES\"><code class=\"xref py py-attr docutils literal notranslate\">request.FILES</code></a>  才会包含文件数据，否则的话， <code class=\"docutils literal notranslate\">request.FILES</code> 是空的。</p>\n<p>绝大多数的情况下，你只需要像 <span class=\"xref std std-ref\">binding-uploaded-files`中所述将文件数据从``request`</span> 传入给 表单，示例如下：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">views.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponseRedirect\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n<span class=\"kn\">from</span> <span class=\"nn\">.forms</span> <span class=\"kn\">import</span> UploadFileForm\n\n<span class=\"c1\"># Imaginary function to handle an uploaded file.</span>\n<span class=\"kn\">from</span> <span class=\"nn\">somewhere</span> <span class=\"kn\">import</span> handle_uploaded_file\n\n<span class=\"k\">def</span> <span class=\"nf\">upload_file</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">:</span>\n        form <span class=\"o\">=</span> UploadFileForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> request<span class=\"o\">.</span>FILES<span class=\"p\">)</span>\n        <span class=\"k\">if</span> form<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            handle_uploaded_file<span class=\"p\">(</span>request<span class=\"o\">.</span>FILES<span class=\"p\">[</span><span class=\"s1\">&#39;file&#39;</span><span class=\"p\">])</span>\n            <span class=\"k\">return</span> HttpResponseRedirect<span class=\"p\">(</span><span class=\"s1\">&#39;/success/url/&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        form <span class=\"o\">=</span> UploadFileForm<span class=\"p\">()</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;upload.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;form&#39;</span><span class=\"p\">:</span> form<span class=\"p\">})</span>\n</code></pre></figure>\n<p>注意我们必须将 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/request-response/#django.http.HttpRequest.FILES\" title=\"django.http.HttpRequest.FILES\"><code class=\"xref py py-attr docutils literal notranslate\">request.FILES</code></a> 传入到表单的\n构造方法中，只有这样文件数据才能绑定到表单中。</p>\n<p>我们通常可能像这样处理上传文件：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">handle_uploaded_file</span><span class=\"p\">(</span>f<span class=\"p\">):</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;some/file/name.txt&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wb+&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> destination<span class=\"p\">:</span>\n        <span class=\"k\">for</span> chunk <span class=\"ow\">in</span> f<span class=\"o\">.</span>chunks<span class=\"p\">():</span>\n            destination<span class=\"o\">.</span>write<span class=\"p\">(</span>chunk<span class=\"p\">)</span>\n</code></pre></div>\n<p>使用 <code class=\"docutils literal notranslate\">UploadedFile.chunks()</code> 而不是 <code class=\"docutils literal notranslate\">read()</code> 是为了确保即使是大文件又不会将我们系统的内存占满。</p>\n<p>There are a few other methods and attributes available on <code class=\"docutils literal notranslate\">UploadedFile</code>\nobjects; see <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile\" title=\"django.core.files.uploadedfile.UploadedFile\"><code class=\"xref py py-class docutils literal notranslate\">UploadedFile</code></a> for a complete reference.</p>\n<section id=\"handling-uploaded-files-with-a-model\">\n<h3>通过模型来处理上传的文件<a class=\"heading-anchor\" href=\"#handling-uploaded-files-with-a-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果想要在 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.FileField\" title=\"django.db.models.FileField\"><code class=\"xref py py-class docutils literal notranslate\">FileField</code></a> 上的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/instances/#django.db.models.Model\" title=\"django.db.models.Model\"><code class=\"xref py py-class docutils literal notranslate\">Model</code></a> 保存文件，使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\">ModelForm</code></a> 会让这一过程变得简单。当调用 <code class=\"docutils literal notranslate\">form.save()</code> 时，文件对象将会被保存在对相应 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.FileField\" title=\"django.db.models.FileField\"><code class=\"xref py py-class docutils literal notranslate\">FileField</code></a> 的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.FileField.upload_to\" title=\"django.db.models.FileField.upload_to\"><code class=\"xref py py-attr docutils literal notranslate\">upload_to</code></a> 参数所指定的地方：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponseRedirect\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n<span class=\"kn\">from</span> <span class=\"nn\">.forms</span> <span class=\"kn\">import</span> ModelFormWithFileField\n\n<span class=\"k\">def</span> <span class=\"nf\">upload_file</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">:</span>\n        form <span class=\"o\">=</span> ModelFormWithFileField<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> request<span class=\"o\">.</span>FILES<span class=\"p\">)</span>\n        <span class=\"k\">if</span> form<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            <span class=\"c1\"># file is saved</span>\n            form<span class=\"o\">.</span>save<span class=\"p\">()</span>\n            <span class=\"k\">return</span> HttpResponseRedirect<span class=\"p\">(</span><span class=\"s1\">&#39;/success/url/&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        form <span class=\"o\">=</span> ModelFormWithFileField<span class=\"p\">()</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;upload.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;form&#39;</span><span class=\"p\">:</span> form<span class=\"p\">})</span>\n</code></pre></div>\n<p>如果你准备手工构建对象，你可以指定来自 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/request-response/#django.http.HttpRequest.FILES\" title=\"django.http.HttpRequest.FILES\"><code class=\"xref py py-attr docutils literal notranslate\">request.FILES</code></a> 的文件对象到模型里的文件对象：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponseRedirect\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n<span class=\"kn\">from</span> <span class=\"nn\">.forms</span> <span class=\"kn\">import</span> UploadFileForm\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> ModelWithFileField\n\n<span class=\"k\">def</span> <span class=\"nf\">upload_file</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">:</span>\n        form <span class=\"o\">=</span> UploadFileForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> request<span class=\"o\">.</span>FILES<span class=\"p\">)</span>\n        <span class=\"k\">if</span> form<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            instance <span class=\"o\">=</span> ModelWithFileField<span class=\"p\">(</span>file_field<span class=\"o\">=</span>request<span class=\"o\">.</span>FILES<span class=\"p\">[</span><span class=\"s1\">&#39;file&#39;</span><span class=\"p\">])</span>\n            instance<span class=\"o\">.</span>save<span class=\"p\">()</span>\n            <span class=\"k\">return</span> HttpResponseRedirect<span class=\"p\">(</span><span class=\"s1\">&#39;/success/url/&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        form <span class=\"o\">=</span> UploadFileForm<span class=\"p\">()</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;upload.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;form&#39;</span><span class=\"p\">:</span> form<span class=\"p\">})</span>\n</code></pre></div>\n</section>\n<section id=\"uploading-multiple-files\">\n<h3>上传多个文件<a class=\"heading-anchor\" href=\"#uploading-multiple-files\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你想使用一个表单字段上传多个文件，则需要设置字段的 widget 的 <code class=\"docutils literal notranslate\">multiple</code> HTML 属性。</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">forms.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django</span> <span class=\"kn\">import</span> forms\n\n<span class=\"k\">class</span> <span class=\"nc\">FileFieldForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>Form<span class=\"p\">):</span>\n    file_field <span class=\"o\">=</span> forms<span class=\"o\">.</span>FileField<span class=\"p\">(</span>widget<span class=\"o\">=</span>forms<span class=\"o\">.</span>ClearableFileInput<span class=\"p\">(</span>attrs<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">&#39;multiple&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">}))</span>\n</code></pre></figure>\n<p>然后覆盖 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView\" title=\"django.views.generic.edit.FormView\"><code class=\"xref py py-class docutils literal notranslate\">FormView</code></a> 子类的 <code class=\"docutils literal notranslate\">post</code> 方法来控制多个文件上传：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">views.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.views.generic.edit</span> <span class=\"kn\">import</span> FormView\n<span class=\"kn\">from</span> <span class=\"nn\">.forms</span> <span class=\"kn\">import</span> FileFieldForm\n\n<span class=\"k\">class</span> <span class=\"nc\">FileFieldView</span><span class=\"p\">(</span>FormView<span class=\"p\">):</span>\n    form_class <span class=\"o\">=</span> FileFieldForm\n    template_name <span class=\"o\">=</span> <span class=\"s1\">&#39;upload.html&#39;</span>  <span class=\"c1\"># Replace with your template.</span>\n    success_url <span class=\"o\">=</span> <span class=\"s1\">&#39;...&#39;</span>  <span class=\"c1\"># Replace with your URL or reverse().</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">post</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> <span class=\"o\">*</span>args<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        form_class <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>get_form_class<span class=\"p\">()</span>\n        form <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>get_form<span class=\"p\">(</span>form_class<span class=\"p\">)</span>\n        files <span class=\"o\">=</span> request<span class=\"o\">.</span>FILES<span class=\"o\">.</span>getlist<span class=\"p\">(</span><span class=\"s1\">&#39;file_field&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> form<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            <span class=\"k\">for</span> f <span class=\"ow\">in</span> files<span class=\"p\">:</span>\n                <span class=\"o\">...</span>  <span class=\"c1\"># Do something with each file.</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span>form_valid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span>form_invalid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n</code></pre></figure>\n</section>\n</section>\n<section id=\"upload-handlers\">\n<h2>上传 Handlers<a class=\"heading-anchor\" href=\"#upload-handlers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当一个用户上传文件时，Django 会把文件数据传递给 <em>upload handler</em> —— 这是一个很小的类，它用来在上传时处理文件数据。上传处理模块最初定义在 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-FILE_UPLOAD_HANDLERS\"><code class=\"xref std std-setting docutils literal notranslate\">FILE_UPLOAD_HANDLERS</code></a> 里，默认为：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"p\">[</span><span class=\"s2\">&quot;django.core.files.uploadhandler.MemoryFileUploadHandler&quot;</span><span class=\"p\">,</span>\n <span class=\"s2\">&quot;django.core.files.uploadhandler.TemporaryFileUploadHandler&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p><a class=\"reference internal\" href=\"/zh-hans/2.2/ref/files/uploads/#django.core.files.uploadhandler.MemoryFileUploadHandler\" title=\"django.core.files.uploadhandler.MemoryFileUploadHandler\"><code class=\"xref py py-class docutils literal notranslate\">MemoryFileUploadHandler</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/files/uploads/#django.core.files.uploadhandler.TemporaryFileUploadHandler\" title=\"django.core.files.uploadhandler.TemporaryFileUploadHandler\"><code class=\"xref py py-class docutils literal notranslate\">TemporaryFileUploadHandler</code></a> 提供 Django 默认文件上传行为，小文件读入内存，大文件存在磁盘上。</p>\n<p>你可以编写自定义的 handlers 来自定义 Django 如何处理文件。比如，你可以使用自定义的 handlers 来强制处理用户层面的配额，动态压缩数据，渲染进度条，甚至可以将数据发送到其他存储地址而不是本地。查看 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/files/uploads/#custom-upload-handlers\"><span class=\"std std-ref\">Writing custom upload handlers</span></a> 来了解你如何自定义或者完全替换上传行为。</p>\n<section id=\"where-uploaded-data-is-stored\">\n<h3>上传数据的存储<a class=\"heading-anchor\" href=\"#where-uploaded-data-is-stored\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在保存上传的文件之前，数据需要保存到某处。</p>\n<p>默认情况下，如果上传的文件小于2.5兆，Django 将把文件的所有内容保存到内存里。这意味着保存文件只涉及从内存中读取和写入磁盘，因此这很快。</p>\n<p>但如果上传的文件很大，Django 会把文件写入系统临时目录的临时文件里存储。在类 Unix 平台里这意味着 Django 会生成一个类似名为 <code class=\"docutils literal notranslate\">/tmp/tmpzfp6I6.upload</code> 的文件。如果上传的文件非常大，你可以查看这个文件的大小增长，因为 Django 将数据流式传输到磁盘上。</p>\n<p>2.5 megabytes; <code class=\"docutils literal notranslate\">/tmp</code>; 等这些细节只是合理的默认值，在下一节要介绍它们如何被自定义。</p>\n</section>\n<section id=\"changing-upload-handler-behavior\">\n<h3>改变上传处理行为<a class=\"heading-anchor\" href=\"#changing-upload-handler-behavior\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>这里有一些控制 Django 文件上传行为的配置，请查看 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#file-upload-settings\"><span class=\"std std-ref\">File Upload Settings</span></a> 。</p>\n</section>\n<section id=\"modifying-upload-handlers-on-the-fly\">\n<span id=\"id1\"></span><h3>动态修改上传处理程序<a class=\"heading-anchor\" href=\"#modifying-upload-handlers-on-the-fly\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>有时候某些视图需要不同的上传行为。在这些例子里，你可以基于每个请求覆盖上传处理程序。默认情况下，这个列表将包含由 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-FILE_UPLOAD_HANDLERS\"><code class=\"xref std std-setting docutils literal notranslate\">FILE_UPLOAD_HANDLERS</code></a> 设置的上传处理程序，但你可以像修改其他列表一样修改这个列表。</p>\n<p>比如，假设你正在编写 <code class=\"docutils literal notranslate\">ProgressBarUploadHandler</code> ，来提供在上传过程中的反馈给 Ajax widget。你需要添加这个处理程序到你的上传处理模块：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>request<span class=\"o\">.</span>upload_handlers<span class=\"o\">.</span>insert<span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> ProgressBarUploadHandler<span class=\"p\">(</span>request<span class=\"p\">))</span>\n</code></pre></div>\n<p>你或许想在这里使用 <code class=\"docutils literal notranslate\">list.insert()</code> （而不是 <code class=\"docutils literal notranslate\">append()</code> ），因为进度条处理程序需要在其他处理程序之前使用。记住，上传处理程序是按顺序处理的。</p>\n<p>如果你想完全替换上传处理程序，你只需要指定新列表：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>request<span class=\"o\">.</span>upload_handlers <span class=\"o\">=</span> <span class=\"p\">[</span>ProgressBarUploadHandler<span class=\"p\">(</span>request<span class=\"p\">)]</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>你只能在访问 <code class=\"docutils literal notranslate\">request.POST</code> 或 <code class=\"docutils literal notranslate\">request.FILES</code> 之前修改上传处理程序，开始上传处理后修改上传处理程序没有意义。如果你从读取 <code class=\"docutils literal notranslate\">request.POST</code> 或 <code class=\"docutils literal notranslate\">request.FILES</code> 之后尝试修改 <code class=\"docutils literal notranslate\">request.upload_handlers</code> ，Django 会报错。</p>\n<p>因此，你要尽早在视图里修改上传处理程序。</p>\n<p>而且， <code class=\"docutils literal notranslate\">request.POST</code> 由 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/middleware/#django.middleware.csrf.CsrfViewMiddleware\" title=\"django.middleware.csrf.CsrfViewMiddleware\"><code class=\"xref py py-class docutils literal notranslate\">CsrfViewMiddleware</code></a> 访问，默认情况下已开启。这意味着你需要在视图上使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/csrf/#django.views.decorators.csrf.csrf_exempt\" title=\"django.views.decorators.csrf.csrf_exempt\"><code class=\"xref py py-func docutils literal notranslate\">csrf_exempt()</code></a> 来允许你改变上传处理程序。然后你需要在实际处理请求的函数上使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/csrf/#django.views.decorators.csrf.csrf_protect\" title=\"django.views.decorators.csrf.csrf_protect\"><code class=\"xref py py-func docutils literal notranslate\">csrf_protect()</code></a> 。注意这可能会让处理程序在 CSRF 检测完成之前开始接受文件上传。示例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.views.decorators.csrf</span> <span class=\"kn\">import</span> csrf_exempt<span class=\"p\">,</span> csrf_protect\n\n<span class=\"nd\">@csrf_exempt</span>\n<span class=\"k\">def</span> <span class=\"nf\">upload_file_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    request<span class=\"o\">.</span>upload_handlers<span class=\"o\">.</span>insert<span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> ProgressBarUploadHandler<span class=\"p\">(</span>request<span class=\"p\">))</span>\n    <span class=\"k\">return</span> _upload_file_view<span class=\"p\">(</span>request<span class=\"p\">)</span>\n\n<span class=\"nd\">@csrf_protect</span>\n<span class=\"k\">def</span> <span class=\"nf\">_upload_file_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"o\">...</span> <span class=\"c1\"># Process request</span>\n</code></pre></div>\n</aside>\n</section>\n</section>","rootId":"file-uploads","toc":[{"title":"简单文件上传","anchor":"basic-file-uploads","children":[{"title":"通过模型来处理上传的文件","anchor":"handling-uploaded-files-with-a-model","children":[]},{"title":"上传多个文件","anchor":"uploading-multiple-files","children":[]}]},{"title":"上传 Handlers","anchor":"upload-handlers","children":[{"title":"上传数据的存储","anchor":"where-uploaded-data-is-stored","children":[]},{"title":"改变上传处理行为","anchor":"changing-upload-handler-behavior","children":[]},{"title":"动态修改上传处理程序","anchor":"modifying-upload-handlers-on-the-fly","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/2.2/topics/"},{"docname":"topics/http/index","title":"处理 HTTP 请求","url":"/zh-hans/2.2/topics/http/"}],"prev":{"docname":"topics/http/decorators","title":"视图装饰器","url":"/zh-hans/2.2/topics/http/decorators/"},"next":{"docname":"topics/http/shortcuts","title":"Django快捷函数","url":"/zh-hans/2.2/topics/http/shortcuts/"},"formats":{"html":"/zh-hans/2.2/topics/http/file-uploads/","markdown":"/zh-hans/2.2/topics/http/file-uploads.md","json":"/zh-hans/2.2/topics/http/file-uploads.json"},"source":"https://github.com/django/django/blob/stable/2.2.x/docs/topics/http/file-uploads.txt","official":"https://docs.djangoproject.com/zh-hans/2.2/topics/http/file-uploads/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}