某些時候可能有這樣的需求,在網頁中點擊一個鏈接或者一個按鈕希望返回一張圖片、一個pdf文檔、一個csv文檔等而非HTML。在diango中很容易做到這些。Django中的view用來接收http request並返回web response。通常情況下,返回的內容為HTML,但其能夠返回的不僅僅如此,還可以是上述圖片、pdf文件等等。返回非HTML形式的內容的關鍵在於HttpResponse這個類,尤其是mimetype這個參數,通過將此參數設置為不同的值可以提示浏覽器view返回了不同格式的內容。比如,想要返回圖片內容,只需讀如一張圖片,然後在HttpResponse中指明圖片的mimetype並將圖片內容作為另一參數response給浏覽器,浏覽器能夠自動正確的顯示圖片內容。
from django.http import HttpResponse
def my_image(request):
image_data = open("/path/to/my/image.png", "rb").read()
return HttpResponse(image_data, mimetype="image/png")
另外一個需要特別注意的的是HttpResponse對象實現了Python的標准“file-like-object”API,也即可以將HttpResponse當做文件使用。
例子:
生成CSV格式的內容
import csv
from django.http import HttpResponse
# Number of unruly passengers each year 1995 - 2005. In a real application
# this would likely come from a database or some other back-end data store.
UNRULY_PASSENGERS = [146,184,235,200,226,251,299,273,281,304,203]
def unruly_passengers_csv(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=unruly.csv'
# Create the CSV writer using the HttpResponse as the "file."
writer = csv.writer(response)
writer.writerow(['Year', 'Unruly Airline Passengers'])
for (year, num) in zip(range(1995, 2006), UNRULY_PASSENGERS):
writer.writerow([year, num])
return response
需要注意的幾點:
1.HttpResponse中mimetype指定為了'text/csv'告知浏覽器返回的文檔是CSV文件。
2.HttpResponse設置了另外一個參數Content-Disposition其中attachment告知浏覽器保存返回的文檔而非顯示其內容,filename指明了返回文檔的名字,改名字可任意指定。
3.因為csv的writer方法期望一個文件類型的對象作為參數,而HttpResponse實例可以當做文件使用,所以可以直接在csv模塊的writer方法中將HttpResponse作為參數。
4.writer.writerow方法負責往文件中寫入一行內容。
上述方法是返回非HTML格式內容的通用模式,也即:創建一個特定MIME Type的HttpResponse,將其傳遞給以文件為參數產生特定格式的文檔的方法,之後返回該response。
生成PDF格式的內容
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def hello_pdf(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=hello.pdf'
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
流程基本同上,需要注意的幾點:
1.此處使用了 application/pdf MIME type告知浏覽器返回的是PDF文件,而非HTML,否則浏覽器會將其作為普通HTML內容處理。
2.canvas.Canvas方法期望一個file-like的對象作為參數,將HttpResponse傳遞給該方法。
3.使用Canvas實例的方法繪制PDF文檔,調用showPage()方法和save()方法(否則會產生損壞的pdf文檔)。
4.最後返回該HttpResponse實例
生成更為復雜的PDF文檔,這裡使用了cStringIO庫來臨時存放PDF文件
from cStringIO import StringIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def hello_pdf(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=hello.pdf'
temp = StringIO()
# Create the PDF object, using the StringIO object as its "file."
p = canvas.Canvas(temp)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the value of the StringIO buffer and write it to the response.
response.write(temp.getvalue())
return response
其他可能的格式
實質上,任何可以寫文件的Python庫都可與Django的HttpResponse結合用以返回特定格式的內容,如ZIP文件、動態圖片、圖表、XLS文件等等。
最後在看一個返回xls文件的例子
from django.http import HttpResponse
import xlwt
def viewXls(request):
response = HttpResponse(mimetype='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=request.xls'
book = xlwt.Workbook(encoding='utf8')
sheet = book.add_sheet('untitled')
for row, column, value in ((0,0,1),(0,1,2),(1,0,3),(1,1,4))
sheet.write(int(row),int(column),value)
book.save(response)
return response
流程同上,不在注釋。
另外,需要特別注意的是,這裡的request必須是通過表單提交才能正確返回特定格式的內容,若要是通過ajax方式發起的request則返回的內容會被當做文本串處理,而不能被浏覽器解釋為特定內容。
比如:
$.ajax({
url:"{% url 'mycitsm.views.viewXls' %}",
data:postData,
type:"POST",
success:function(result){
},
});
//是不可以的,而要使用如下的表單提交才可以:
var form = $("#xlsForm");
form.attr({
action:"{% url 'mycitsm.views.returnXls' %}",
method:"POST"
});
form.submit();
說到這裡有必要記錄一下開發過程中遇到的一個問題,也即將表單內容序列化為字符串的問題。
有時需將表單中的所有內容序列化為鍵值對構成的串做為一個整體進行URL參數傳遞,而且需要對值中包含的特殊字符進行編碼。比如有如下表單:
<form>
<div><input type="text" name="a" value="1" id="a" /></div>
<div><input type="text" value="2" id="b" /></div>
<div><input type="hidden" name="c" value="3" id="c" /></div>
<div>
<textarea name="d" rows="8" cols="40">4</textarea>
</div>
<div><select name="e">
<option value="5" selected="selected">5</option>
<option value="6">6</option>
<option value="7">7</option>
</select></div>
<div>
<input type="checkbox" name="f" value="8" id="f" />
</div>
<div>
<input type="submit" name="g" value="Submit" id="g" />
</div>
</form>
$('form').submit(function() {
alert($(this).serialize());
return false;
});
#可以輸出
a=1&c=3&d=4&e=5
為什麼第二個text類型的input的值還有checkbox類型的input的值以及submit類型的input沒有被序列化呢?這是因為如果要表單元素的值包含到序列字符串中,元素必須使用 name 屬性。而第二個text類型的input無name屬性。checkbox類型的input有一個並沒有被checked所以……。serialize()只會將”成功的控件“序列化為字符串。如果不使用按鈕來提交表單,則不對提交按鈕的值序列化,所以submit類型的input沒有被序列化。
當然除了直接對整個form序列化外還可對已選取的個別表單元素的jQuery對象序列化,如<input>,<textarea>等等。
Ubuntu Server 12.04 安裝Nginx+uWSGI+Django環境 http://www.linuxidc.com/Linux/2012-05/60639.htm
Django+Nginx+uWSGI 部署 http://www.linuxidc.com/Linux/2013-02/79862.htm
Django實戰教程 http://www.linuxidc.com/Linux/2013-09/90277.htm
Django Python MySQL Linux 開發環境搭建 http://www.linuxidc.com/Linux/2013-09/90638.htm
Ubuntu Server 14.04.2 LTS 配置 Nginx + Uwsgi + Django http://www.linuxidc.com/Linux/2015-04/116397.htm
CentOS 5.5 + Nginx 0.8.50 + uWSGI + Django 1.2.3 部署Django項目 http://www.linuxidc.com/Linux/2011-05/36399.htm
Django 的詳細介紹:請點這裡
Django 的下載地址:請點這裡