我學習django的主要途徑是http://djangobook.com, 作者的書好像也出版了。作者的思路很清爽,講解淺顯易懂,該深入的地方深入,我很喜歡,比django官方文檔感覺好多了,官方文檔講解的太晦澀。這些隨筆是結合一些例子來細說django的學習要點與本人的學習心得。
有些中文博客也講解了用django做一些小的項目,但是沒有細講django的原理,即為什么要這樣做,我就個人的理解會細致地講解各個部分的知識點。希望能幫助更多人,也希望與更多人一起進步。
本人配置環境:(2017.6.20)
注意: 在windows中的文件系統是用反斜杠'\'來表示,但是即使是在windows系統下的django,在表示文件路徑時依然用unix 風格的斜杠'/'
OS: win7
python:3.6.2
Django: 1.11.2
創建項目與應用
每個項目的前部分:創建項目與應用,把應用添加到settings.py 的'INSTALLED_APP'里,在settings.py里設置默認的數據庫,並同步數據庫數據的操作都是一樣的,就不具體敘述,可以參考我前面的例子。
我把這個上傳文件的項目命名為disk, 項目名稱為mysite,創建完成后的結構如下:(disk/templates, disk/uploads, disk/forms.py 是我本人創建的,不是系統創建的。請忽略除mysite, disk以外的部分,與此例無關。)

# Application definition INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'disk', )
創建Form類實例
為了簡單起見,在這個文件上傳系統中,我們只設計兩個變量:上傳文件的用戶改名,及上傳的文件。Django中為用戶定義了一個django.forms庫,這個庫可以方便地進行form類的數據顯示及數據驗證,省去了很多用戶的代碼。django.forms庫用起來也方便,只需要在HTML文件中需要增加<form> tag時,定義相應的 Form 類就可以。在以下的示例中我們最終的頁面上只有一個<form> tag, 所以我們只需要定義一個Form類即可。Django 社區的慣例是把Form類單獨放在一個forms.py文件中,我們最好也遵循這個規則。創建disk\forms.py文件,並寫入:
# mysite\disk\forms.py from django import forms class UserForm(forms.Form): userName = forms.CharField(max_length = 20) uploadFile = forms.FileField()
可以看出Form類的語法與定義Model時的語法很像,對於每個變量都要定義它的域的屬性,這個我在下面的Model章節中會仔細再講。在UserForm中,我們定義了userName,它是字符屬性,還定義了uploadFile,它是文件屬性。默認情況下這兩個變量都是不能為空的,如果為空,則會在html頁面中顯示出相應的錯誤。
創建Models(數據庫層)
我們需要把用戶名和上傳的文件路徑放到數據庫中, 所以在設計數據庫時需要兩個字段:userName and uploadFile。在disk\models.py文件中寫入:
# disk\models.py from django.db import models # Create your models here. class User(models.Model): userName = models.CharField(max_length = 30) uploadFile = models.FileField(upload_to = 'disk/upload/') def __str__(self): return self.userName
對於models的定義,要講的東西很多。
- 每個變量都要定義成某種類型的域(field),django會根據不同的域來決定某些事情。比如,域的類型會決定數據庫中該變量的數據類型(比如INTERGER, VARCHAR)。對於每個變量,在html顯示層,django把它定義成一個單獨的widget。最終是以什么widget顯示變量也是與該域的類型有關的,比如一個CharField變量最終會以<input type= 'text'>的形式顯現。
- 以下是每種域類型變量的定義,來自http://www.djangobook.com/model-definition-reference/。為了保證釋義的完整性與准確性,我就不翻譯成中文了:






下張表是所有域通用的可選參數:





- FileFiled 說明:此類變量不支持primary_key, unique參數(見上表)。有兩個可選參數:upload_to和storage。'upload_to'定義的是一個本地的文件路徑,這個路徑可以是個相對路徑,它會自動加到settings.py文件中 BASE_DIR 目錄的后面。一般情況下,即使文件上傳成功也不會保存到數據庫中,除非顯性的調用save()函數。從性能上考慮,不會把上傳的文件存儲到數據庫中,而是把文件的路徑存儲到數據庫中(如果調用了save()函數)。
- 在定義完models后,要把它同步到數據庫中,主要用兩個命令python manage.py makemigrations, python manage.py migrate
創建Views (邏輯層)
視圖views決定的是按照怎樣的邏輯收集處理數據,並把用戶的數據呈現給用戶;可以把它理解成用戶數據(數據庫)到最終呈現頁面(web頁面)的中間人。這部分一般就是純粹的python代碼。打開mysite\disk\views.py文件並寫入:
# mysite\disk\views.py from django.shortcuts import render from disk.forms import UserForm from disk.models import User def uploads(request): if request.method == 'POST': userform = UserForm(request.POST, request.FILES) if userform.isValid(): user = User() user.userName = userform.cleaned_data['userName'] user.uploadFile = userform.cleaned_data['uploadFile'] user.save() return render(request, 'uploadOK.html') else: userform = UserForm(initial ={'userName': 'sunshore'}) return render(request, 'upload.html', {'userform': userform})
views.py文件就把上文定義的UserForm和User (models文件)引用了過來。
- 對於HttpRequest.POST對象,我們在上一節中講過,這里不再敘述。
- HttpRequest.FILES對象也是一個“類字典”對象,它的'key'是文件名,與html文件中<input type = "file" name = "" />中的內容相同;'key'所對應的'value' 是上傳的文件。注意: 這個對象必須是在HttpRequest method = 'POST' 並且<form> tag中包含 enctype="multipart/form-data"時才會有值,否則會返回一個空的類字典對象。
- django中Form類實例化后,可以通過isValid()函數來檢查數據是否有效;如果有效,則該實例就會有cleaned_data屬性,這是一個字典對象,包含的是Form類數據。
- 我們首先檢查HttpRequest是一個POST 方法,然后實例化Form類,如果實例化成功,就把數據存儲到數據庫中去。(當然最終存儲到數據庫中不是文件本身,而是文件路徑,上部分提到過)。如果HttpRequest不是POST方法,則把用戶名初始化成'sunshore'。
創建Templates(顯示層)
我們需要創建templates來定制數據的顯示。Django中將數據的處理與顯示分開了,數據的處理是在views.py中,數據的顯示是在templates里。 默認情況下,mysite/mysite/settings.py文件中的TEMPLATES定義'APP_DIRS' = True, 也就是說django會到各個應用的文件下尋找templates文件夾,使用里面定義的html文件。
我們需要在mysite/disk/templates創建兩個html文件:upload.html和uploadOK.html,並寫入:
# mysite\disk\templates\upload.html <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head>
<style type="text/css">
ul.errorlist{
margin:0;
padding:0;
}
.errorlist li{
background-color: blue;
color: white;
display: block;
font-size: 1.0em;
margin: 0 0 1px;
padding: 0 10px;
}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Upload File</title> </head> <body> <h1>User Upload Files</h1> <form action="" method="post" enctype="multipart/form-data" > {{userform.as_p}} {% csrf_token %} <input type="submit" value="ok"/> </form> </body> </html>
# mysite\disk\templates\uploadOK.html <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Upload OK</title> </head> <body> <p > Uploading Files Successfully </p> <a href= 'upload'>Back to upload file page </a> </body> </html>
- Form類會自動生成頁面的錯誤信息,並以errorlist的形式返回結果。在html文件中我們可以對errorlist進行CSS的定制,使得error信息更為突出。這就是<style> ....</style>那段代碼的作用。
- 默認情況下,Form類顯示成員的排版格式有form.as_p, form.as_table, form.as_ul這三種形式,不同形式下成員的排列是不同的。比如本示例中userform.as_p會顯示如下:

userform.as_table 顯示結果:

userform.as_ul 顯示結果:

我們可以根據自己的喜好來選擇成員的顯示形式。當然django也支持自己定制所有成員的顯示形式。感興趣的讀者可以參考:http://djangobook.com/tying-forms-views.
設置urlconf 文件
這個是用正則表達式的方式定義了HttpRequest.url和views的對應關系。在mysite\urls.py文件中輸入:
# mysite\urls.py from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() from disk import views as disk_views urlpatterns = patterns('', # Examples: # url(r'^$', 'mysite2.views.home', name='home'), # url(r'^blog/', include('blog.urls')), url(r'^admin/', include(admin.site.urls)), url(r'^upload/$', disk_views.upload), )
啟動服務
在mysite文件夾下,終端命令行輸入: python manage.py runserver 80
在用戶正確地上傳了文件后,我們可以在mysite\disk\upload文件夾下看到此文件,這個是在models.py里定義的,讀者們可以試一下。
