Django是Python語言編寫的一個全棧式Web架構,可以幫助我們快速編寫一個具有資料庫功能、增删查改、背景管理等功能的網站。假如你隻需要一些很簡單的功能,使用flask可能是個更好的選擇。但是如果你想快速實作一個XX管理系統,那麼用Django絕對是個好辦法。本文參考了Django官方文檔的 Tutorials 。另外我這裡用的終端是Powershell,如果有些指令不能運作,去掉前面的 .\
。
快速開始
安裝Django
首先安裝Django包,現在Django已經到了2.0版本,如果還在使用1.11請盡快更新。舊版本以後隻修複bug,不會添加新功能。
pip install django
建立項目
Django安裝好之後,會附帶一個指令行工具
django-admin
,可以幫助我們管理Django項目。我們可以使用下面的指令建立一個新的Django項目模闆。這樣會建立
django_sample
檔案夾,項目檔案就在其中。另外需要注意項目檔案夾最好是個性化一點的,不要和django、sys這樣的第三方庫或者python系統庫重名。
django-admin startproject hello_django
建立好項目之後,我們進入項目檔案夾中。用下面的指令就可以運作Django項目了。預設情況下,我們可以通過
http://127.0.0.1:8000/來通路正在運作的項目。由于沒有任何頁面,是以會顯示這麼一個調試視窗。
python manage.py runserver

運作成功
建立app
在Django項目中,app表示更小的一個功能機關,比方說在一個部落格管理系統中,對部落格的增删查改等功能就應該聚合在一個app中。進入項目目錄中,用
startapp
指令建立app。
cd .\hello_django\
django-admin startapp hello
這時候項目目錄結構應該類似這樣。
目錄結構
為了讓django包含建立的app,我們還需要激活app。打開配置檔案,找到
INSTALLED_APPS
,然後把我們建立的app配置添加進去,這樣django才能使用我們的app。
INSTALLED_APPS = [
'hello.apps.HelloConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
模型層
設定資料庫
打開配置檔案
settings.py
,找到資料庫一行,可以看到如下的配置。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
如果我們這時候使用
python .\manage.py migrate
指令生成資料庫表,就會在項目中出現一個
db.sqlite3
檔案,這就是預設的資料庫檔案,使用IDEA右鍵點選并選擇
As DataSource
就可以将其作為資料庫打開。然後我們會看到生成了10多個資料庫表,這是Django程式存儲資料生成的表。
django系統表
除了sqlite資料庫,django還支援POstgreSQL、MySQL、Oracle這幾個資料庫。如果添加第三方後端支援,還可以使用SQL Server、IBM DB2等資料庫。例如我現在準備使用PostgreSQL資料庫,就修改為下面的配置。這時候NAME屬性的意義就是資料庫的名字。另外必須確定資料庫事先存在,django可以自動建立表,但是不能自動建立資料庫。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'test',
'USER': 'postgres',
'PASSWORD': '12345678',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
建立模型
django支援ORM模型,也就是說我們可以不使用SQL語句就對資料進行增删查改。我們要做的就是在模型中指定和資料庫的關系。
打開hello app中的
models.py
檔案,然後添加下面兩個模型。這兩個模型是寵物和主人的關系。如果使用過其他ORM架構比如Hibernate之類的話,對這種結構應該非常熟悉。我們在定義模型的時候指定每一個字段的名字、長度、是否唯一等資訊。值得注意的是,如果需要的值隻可能是幾個固定值,可以定義一個元組(該元組有一對值構成,第一個值是實際存在資料庫中的值,第二個是給人類顯示的友好可讀值),然後傳入
choices
參數。
models.ForeignKey
用來指定外鍵限制,還有一些其他的對應關系例如多對多、一對一等就不介紹了。
from django.db import models
class Owner(models.Model):
GENDER = (
('M', 'MALE'),
('F', 'FEMALE')
)
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30, unique=True)
gender = models.CharField(max_length=1, choices=GENDER)
birthday = models.DateField()
class Pet(models.Model):
TYPE = (
('C', 'Cat'),
('D', 'Dog')
)
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(Owner, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
type = models.CharField(max_length=1, choices=TYPE)
生成并應用遷移檔案
上面我們建立了兩個模型,實際上,隻要我們對模型進行了更改,就應該使用下面的指令生成這些更改。
python manage.py makemigrations hello
Migrations for 'hello':
hello\migrations\0001_initial.py
- Create model Owner
- Create model Pet
并且在
migration
檔案夾中生成了對應的遷移檔案。
如果想知道遷移檔案會具體生成什麼樣的SQL語句,可以調用下面的指令。這裡的序号是遷移序号,每次對模型進行更改都會生成一個新的遷移檔案,想檢視哪個檔案生成的SQL語句,就指定哪個序号。
python manage.py sqlmigrate hello 0001
結果應該類似下面這樣。
BEGIN;
--
-- Create model Owner
--
CREATE TABLE "hello_owner" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL UNIQUE, "gender" varchar(1) NOT NULL, "birthday" date NOT NULL);
--
-- Create model Pet
--
CREATE TABLE "hello_pet" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(50) NOT NULL, "type" varchar(1) NOT NULL, "owner_id" integer NOT NULL REFERENCES "hello_owner" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "hello_pet_owner_id_a7d7b3df" ON "hello_pet" ("owner_id");
COMMIT;
當然這隻是生成了遷移檔案,并沒有真正應用到資料庫中。如果要引用到資料庫,再次使用migrate指令即可。這時候再次檢視資料庫,就會發現多了hello_owner和hello_pet兩個表,正好對應我們的兩個模型。
python manage.py migrate
資料操作
用下面的指令打開django Shell。
python manage.py shell
如果不想使用指令,也可以設定
DJANGO_SETTINGS_MODULE
環境變量的項目的
settings.py
檔案,然後在python解釋器中設定django shell。
>>> import django
>>> django.setup()
不管是用哪種方法,都可以打開shell,在這裡面就可以使用API操作資料了。首先引入我們的模型。
In [1]: from hello.models import Owner, Pet
增加一些資料。
In [4]: o1=Owner(name='zhang3',birthday='1992-5-7',gender='M')
In [5]: o1.save()
In [6]: o2=Owner(name='limei',birthday='1996-6-8',gender='F')
In [7]: o2.save()
In [8]: p1=Pet(owner=o1,name='lele',type='D')
In [9]: p1.save()
下面是一些查詢例子,get函數查詢單個模型,filter函數查詢多個模型,all函數查詢所有模型。
In [7]: Pet.objects.all()
In [8]: Pet.objects.get(id=1)
In [11]: Owner.objects.get(name='zhang3')
In [14]: Owner.objects.filter(gender='M')
In [18]: Owner.objects.count()
上面的隻能執行精确查找某個字段,如果需要更複雜的可以使用雙下劃綫加查詢謂詞的形式。詳細文檔參考
https://docs.djangoproject.com/en/2.0/topics/db/queries/#field-lookups-introIn [20]: Owner.objects.filter(name__startswith='z')
In [22]: Owner.objects.filter(birthday__year__lte='1994')
In [30]: Owner.objects.filter(name__contains='5')
删除某個對象。
In [31]: p2.delete()
為了調試更友善,我們還可以在這兩個模型上添加str函數。這樣調試的時候就更加易讀了。
class Owner(models.Model):
def __str__(self):
return f'Owner(id:{self.id}, name:{self.name}, gender:{self.gender}, birthday:{self.birthday}'
class Pet(models.Model):
def __str__(self):
return f'Pet(id:{self.id}, name:{self.name}, type:{self.type}'
Django Admin
Django Admin可以幫助我們快速管理背景資料。首先需要建立一個管理者賬戶。
python manage.py createsuperuser
建立完成後,通過
http://127.0.0.1:8000/admin/通路管理者界面并輸入剛才設定的管理者和密碼,會看到如下的界面。
管理者界面
這裡目前什麼都沒有,我們需要将模型注冊到Admin中。打開
admin.py
檔案,輸入下面的内容。
from django.contrib import admin
# Register your models here.
from .models import Owner, Pet
admin.site.register(Owner)
admin.site.register(Pet)
這樣一來,就可以在管理者界面中管理模型了。
管理模型
頁面和視圖
路由
首先在app的
views.py
中添加一個新的視圖。不過按照Spring MVC的分層,我覺得這裡的這些視圖叫控制器似乎更合理一些,不過既然這個檔案都叫做view,那麼我也叫它視圖吧。
from django.http import HttpResponse
def index(request):
return HttpResponse('hello')
然後在app中建立一個
urls.py
檔案,寫入以下内容。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
然後在項目的
urls.py
檔案中添加app中設定的路徑,除了admin頁面的路徑之外,其他路徑都應該使用include函數引入。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('hello/', include('hello.urls'))
]
然後通路
http://127.0.0.1:8000/hello/,應該就可以看到顯示的字元串了。
路徑參數
如果路由是帶路徑參數的,那麼使用
<類型:變量名>
文法。
urlpatterns = [
path('', views.index, name='index'),
path('hello/<str:name>', views.hello, name='hello')
]
對應的參數作為視圖函數的第二個參數。
def hello(request, name):
return HttpResponse(f'hello, {name}')
這樣,通路
http://127.0.0.1:8000/hello/hello/yitian就可以看到對應的輸出了。
使用模闆
在app中建立
templates/hello
檔案夾,然後在其中建立
index.html
檔案,檔案内容如下。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>Hello,{{ name }}</h1>
</body>
</html>
然後修改view.py檔案,将hello視圖修改為下面的樣子。再次通路就可以看到這次成功的傳回了網頁。
from django.http import HttpResponse
from django.template import loader
def hello(request, name):
template = loader.get_template('hello/index.html')
context = {'name': name}
return HttpResponse(template.render(context, request))
django還提供了快捷render函數可以簡化這個傳回模闆的常見過程。
from django.http import HttpResponse
from django.shortcuts import render
def hello(request, name):
context = {'name': name}
return render(request, 'hello/index.html', context)
有些同學可能有疑問,為什麼模闆檔案夾中還要在建立一個hello子檔案夾呢?這是由于django的檔案搜尋機制所導緻的。當搜尋模闆檔案的時候django會從所有app的templates檔案夾中搜尋,但是并不會區分它們,是以如果在多個app中有相同的檔案名,django會使用找到的第一個。是以為了區分它們我們隻能自己多建立一層檔案夾用于區分。
和flask一樣,django預設使用Jinja2模闆,關于jinja2的文法請查閱相關文檔,這裡就不在詳細說明了。
頁面中使用URL
當我們在頁面中需要使用路徑的時候,不要寫死路徑,最好使用url标簽。例如下面這樣的。
<a href="{% url 'hello' '張三' %}">你好,張三</a>
這裡url标簽中指定的名稱是urls.py檔案中路徑的name參數。
path('hello/<str:name>', views.hello, name='hello')
當項目中存在多個app的時候,需要使用命名空間來區分。做法很簡單,在urls.py檔案中添加app_name屬性。
app_name = 'hello'
urlpatterns = [
path('', views.index, name='index'),
path('hello/<str:name>', views.hello, name='hello')
]
然後在标簽上添加用冒号分隔開的命名空間名稱即可。
<a href="{% url 'hello:hello' '張三' %}">你好,張三</a>
擷取表單參數
在頁面中添加如下一個表單。
{% csrf_token %}
标簽是django内建的功能,可以幫助我們防止csrf攻擊。
<form action="{% url 'hello:form' %}" method="post">
{% csrf_token %}
<label for="name">name</label>
<input type="text" name="name" id="name">
<br/>
<label for="male">male</label>
<input type="radio" name="gender" value="male" id="male">
<label for="female">female</label>
<input type="radio" name="gender" value="female" id="female">
<br>
<label for="age">age</label>
<input type="text" name="age" id="age">
<br>
<input type="submit" value="submit">
</form>
然後添加下面一條路徑。
path('form', views.get_form, name='form')
最後添加處理函數,這個處理函數很簡單,僅僅傳回結果文本。需要擷取參數的時候,直接用request.POST即可,它是一個類似字典的對象,我們可以通過鍵來通路對應參數的值。
def get_form(request):
form = request.POST
return HttpResponse(f"name:{form['name']}, gender:{form['gender']}, age:{form['age']}")
靜态檔案
app内靜态檔案
對于樣式表等靜态檔案,如果是位于app内的,不需要額外設定。隻要在app内建立static檔案夾并将靜态檔案放入即可。之後在頁面中引用的時候添加下面的标簽即可。注意在使用static标簽之前,需要用
{% load static %}
加載它。
{% load static %}
<link rel="stylesheet" href="{% static 'site.css' %}">
檔案結構類似下圖。
靜态檔案結構
需要注意的是,由于前面介紹的django檔案搜尋機制,在靜态檔案夾中,我們最好在指定一級和app同名的檔案夾用來區分不同app間的靜态檔案。
項目公用靜态檔案
有些靜态檔案可能是多個app公用的,這時候需要進行一點額外設定。首先在和app同級的目錄建立static檔案夾并将靜态檔案放入。然後在配置檔案中添加額外的搜尋路徑配置。
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
還是由于django檔案搜尋機制,我們最好在靜态目錄中添加一個public子檔案夾和其他靜态檔案區分。
測試
django支援自動化測試,可以幫助我們快速查找bug。測試檔案應該寫到tests.py檔案中。下面是一個簡單的例子。
from django.test import TestCase
class SampleTest(TestCase):
def test_true(self):
self.assertTrue(True, 'is true')
TestCase基類含有各種斷言方法,可以幫我們進行判斷,這裡就不列舉了。
要運作測試的話,使用下面的指令。可以看到django還會自動建立和删除測試資料庫,非常友善。
PS D:\kang\PycharmProjects\python-study\hello_django> python .\manage.py test hello
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.015s
OK
Destroying test database for alias 'default'...
以上就是一點對于django架構的介紹。希望大家在看完之後可以對django架構有一些基本了解。本來我是準備照着官方文檔的教程來寫的,但是寫了一半感覺教程内容太多,沒辦法放到一篇文章中。是以就寫成了這麼一個虎頭蛇尾的文章。之後有時間我會慢慢寫文章,仔細介紹django的各個方面的内容。