# 文件上傳 #
當Django在處理文件上傳的時候,文件數據被保存在`request. FILES` (更多關于 `request` 對象的信息 請查看 [請求和響應對象](http://python.usyiyi.cn/django/ref/request-response.html))。這篇文檔闡述了文件如何上傳到內存和硬盤,以及如何自定義默認的行為。
> 警告
>
> 允許任意用戶上傳文件是存在安全隱患的。更多細節請在[用戶上傳的內容](http://python.usyiyi.cn/django/topics/security.html#user-uploaded-content-security)中查看有關安全指導的話題。
## 基本的文件上傳 ##
考慮一個簡單的表單,它含有一個`FileField`:
```
# In forms.py...
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
```
處理這個表單的視圖會在`request`中接受到上傳文件的數據。`FILES`是個字典,它包含每個`FileField`的鍵 (或者 `ImageField`,`FileField`的子類)。這樣的話就可以用`request.FILES['file']`來存放表單中的這些數據了。
注意`request.FILES`會僅僅包含數據,如果請求方法為`POST`,并且發送請求的`<form>`擁有`enctype="multipart/form-data"`屬性。否則`request.FILES`為空。
大多數情況下,你會簡單地從`request`向表單中傳遞數據,就像[綁定上傳文件到表單](http://python.usyiyi.cn/django/ref/forms/api.html#binding-uploaded-files)描述的那樣。這樣類似于:
```
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from .forms import UploadFileForm
# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render_to_response('upload.html', {'form': form})
```
注意我們必須向表單的構造器中傳遞`request.FILES`。這是文件數據綁定到表單的方法。
這里是一個普遍的方法,可能你會采用它來處理上傳文件:
```
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
```
遍歷`UploadedFile.chunks()`,而不是使用`read()`,能確保大文件并不會占用系統過多的內存。
`UploadedFile `對象也擁有一些其他的方法和屬性;完整參考請見UploadedFile。
### 使用模型處理上傳文件 ###
如果你在`Model`上使用`FileField`保存文件,使用`ModelForm`可以讓這個操作更加容易。調用`form.save()`的時候,文件對象會保存在相應的`FileField`的`upload_to`參數指定的地方。
```
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField
def upload_file(request):
if request.method == 'POST':
form = ModelFormWithFileField(request.POST, request.FILES)
if form.is_valid():
# file is saved
form.save()
return HttpResponseRedirect('/success/url/')
else:
form = ModelFormWithFileField()
return render(request, 'upload.html', {'form': form})
```
如果你手動構造一個對象,你可以簡單地把文件對象從`request.FILE`賦值給模型:
```
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = ModelWithFileField(file_field=request.FILES['file'])
instance.save()
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
```
## 上傳處理器 ##
當用戶上傳一個文件的時候,Django會把文件數據傳遞給上傳處理器 – 一個小型的類,會在文件數據上傳時處理它。上傳處理器在`FILE_UPLOAD_HANDLERS`中定義,默認為:
```
("django.core.files.uploadhandler.MemoryFileUploadHandler",
"django.core.files.uploadhandler.TemporaryFileUploadHandler",)
```
`MemoryFileUploadHandler` 和`TemporaryFileUploadHandler`一起提供了Django的默認文件上傳行為,將小文件讀取到內存中,大文件放置在磁盤中。
你可以編寫自定義的處理器,來定制Django如何處理文件。例如,你可以使用自定義處理器來限制用戶級別的配額,在運行中壓縮數據,渲染進度條,甚至是向另一個儲存位置直接發送數據,而不把它存到本地。關于如何自定義或者完全替換處理器的行為,詳見[編寫自定義的上傳處理器](http://python.usyiyi.cn/django/ref/files/uploads.html#custom-upload-handlers)。
### 上傳數據在哪里儲存 ###
在你保存上傳文件之前,數據需要儲存在某個地方。
通常,如果上傳文件小于2.5MB,Django會把整個內容存到內存。這意味著,文件的保存僅僅涉及到從內存讀取和寫到磁盤,所以非常快。
但是,如果上傳的文件很大,Django會把它寫入一個臨時文件,儲存在你系統的臨時目錄中。在類Unix的平臺下,你可以認為Django生成了一個文件,名稱類似于`/tmp/tmpzfp6I6.upload`。如果上傳的文件足夠大,你可以觀察到文件大小的增長,由于Django向磁盤寫入數據。
這些特定值 – 2.5 MB,`/tmp`,以及其它 -- 都僅僅是"合理的默認值",它們可以自定義,這會在下一節中描述。
### 更改上傳處理器的行為 ###
Django的文件上傳處理器的行為由一些設置控制。詳見文件上傳設置。
### 在運行中更改上傳處理器 ###
有時候一些特定的視圖需要不同的上傳處理器。在這種情況下,你可以通過修改`request.upload_handlers`,為每個請求覆蓋上傳處理器。通常,這個列表會包含`FILE_UPLOAD_HANDLERS`提供的上傳處理器,但是你可以把它修改為其它列表。
例如,假設你編寫了`ProgressBarUploadHandler`,它會在上傳過程中向某類AJAX控件提供反饋。你可以像這樣將它添加到你的上傳處理器中:
```
request.upload_handlers.insert(0, ProgressBarUploadHandler())
```
在這中情況下你可能想要使用`list.insert()`(而不是`append()`),因為進度條處理器需要在任何其他處理器 之前執行。要記住,多個上傳處理器是按順序執行的。
如果你想要完全替換上傳處理器,你可以賦值一個新的列表:
```
request.upload_handlers = [ProgressBarUploadHandler()]
```
> 注意
>
> 你只可以在訪問`request.POST`或者`request.FILES`之前修改上傳處理器-- 在上傳處理工作執行之后再修改上傳處理就毫無意義了。如果你在讀取`request.FILES`之后嘗試修改`request.upload_handlers`,Django會拋出異常。
>
> 所以,你應該在你的視圖中盡早修改上傳處理器。
>
> `CsrfViewMiddleware` 也會訪問`request.POST`,它是默認開啟的。意思是你需要在你的視圖中使用`csrf_exempt()`,來允許你修改上傳處理器。接下來在真正處理請求的函數中,需要使用`csrf_protect()`。注意這意味著處理器可能會在CSRF驗證完成之前開始接收上傳文件。例如:
```
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt
def upload_file_view(request):
request.upload_handlers.insert(0, ProgressBarUploadHandler())
return _upload_file_view(request)
@csrf_protect
def _upload_file_view(request):
... # Process request
```
> 譯者:[Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html),原文:[Overview](https://docs.djangoproject.com/en/1.8/topics/http/file-uploads/)。
>
> 本文以 [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/cn/) 協議發布,轉載請保留作者署名和文章出處。
>
> [Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html)人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。
- 新手入門
- 從零開始
- 概覽
- 安裝
- 教程
- 第1部分:模型
- 第2部分:管理站點
- 第3部分:視圖和模板
- 第4部分:表單和通用視圖
- 第5部分:測試
- 第6部分:靜態文件
- 高級教程
- 如何編寫可重用的應用
- 為Django編寫首個補丁
- 模型層
- 模型
- 模型語法
- 元選項
- 模型類
- 查詢集
- 執行查詢
- 查找表達式
- 模型的實例
- 實例方法
- 訪問關聯對象
- 遷移
- 模式編輯器
- 編寫遷移
- 高級
- 管理器
- 原始的SQL查詢
- 聚合
- 多數據庫
- 自定義查找
- 條件表達式
- 數據庫函數
- 其它
- 遺留的數據庫
- 提供初始數據
- 優化數據庫訪問
- 視圖層
- 基礎
- URL配置
- 視圖函數
- 快捷函數
- 裝飾器
- 參考
- 內建的視圖
- TemplateResponse 對象
- 文件上傳
- 概覽
- File 對象
- 儲存API
- 管理文件
- 自定義存儲
- 基于類的視圖
- 概覽
- 內建顯示視圖
- 內建編輯視圖
- API參考
- 分類索引
- 高級
- 生成 CSV
- 生成 PDF
- 中間件
- 概覽
- 內建的中間件類
- 模板層
- 基礎
- 面向設計師
- 語言概覽
- 人性化
- 面向程序員
- 表單
- 基礎
- 概覽
- 表單API
- 內建的Widget
- 高級
- 整合媒體
- 開發過程
- 設置
- 概覽
- 應用程序
- 異常
- 概覽
- django-admin 和 manage.py
- 添加自定義的命令
- 測試
- 介紹
- 部署
- 概述
- WSGI服務器
- 部署靜態文件
- 通過email追蹤代碼錯誤
- Admin
- 管理操作
- 管理文檔生成器
- 安全
- 安全概述
- 說明Django中的安全問題
- 點擊劫持保護
- 加密簽名
- 國際化和本地化
- 概述
- 本地化WEB UI格式化輸入
- “本地特色”
- 常見的網站應用工具
- 認證
- 概覽
- 使用認證系統
- 密碼管理
- 日志
- 分頁
- 會話
- 數據驗證
- 其它核心功能
- 按需內容處理
- 重定向
- 信號
- 系統檢查框架