Django是如今世界上python語言應用最普遍、發展最成熟的web框架。它足夠完整 ,不須要依賴其餘就能夠開發出 很是完整的web應用。Django的主要內容以下:html
Django於2003年誕生於美國的堪薩斯州,最初是用來製做在線新聞web網站,於2005年加入了BSD許可證家族,成爲開源網絡框架。Django根據比利時的爵士音樂家Django Reinhardt命名。前端
相對於python的其它web框架,Django的功能是最完整的,Django定義了服務發佈,路由映射,模板編程,數據處理的一整套功能。這也意味着Django模塊之間緊密耦合,開發者須要學習Django本身定義的一整套技術。它的主要特色以下:java
Django是遵循MVC架構的web開發框架,主要又如下幾個部分組成。python
在安裝pip工具的python環境中能夠直接使用pip install django命令進行安裝。或者下載Django的離線包,使用python setup.py install命令進行安裝。mysql
安裝完成後,進入python,經過以下命令測試是否安裝成功。git
import djangoweb
print(django.version)正則表達式
在進行項目開發的第一步就是要創建Django項目,創建的語法以下:sql
django-admin startproject djangotest。數據庫
上述代碼中的django-admin是安裝好Django組件後在python目錄中生成的Django項目管理工具。該命令在當前的目錄下建立了項目工程文件,工程文件中的目錄結構以下:
上圖就是成功生成的項目文件,默認生成的幾個文件很是重要,在從此的開發或者維護中要一直使用它們。各個文件簡單的解釋以下:
爲了在項目中開發符合MVC架構的實際應用程序,咱們須要在項目中創建Django應用。每個django項目能夠包含多個django應用。應用的創建語法以下。
python manage.py startapp app。
其中的manage.py是創建項目是用到的命令行工具,startapp是命令行關鍵字,app是創建的應用名稱。命令完成後會在項目的目錄下創建以下圖所示的文件結構。
其中各個文件功能的說明以下:
在完成django項目和應用的創建後,就能夠開始編寫網站的代碼了,下面簡單演示一下django的路由映射功能。
(1)在app/views.py中建立一個路由響應函數,代碼以下
from django.http import HttpResponse def welcome(request): return HttpResponse('<h1>你好,django</h1>')
(2)接下來,要經過URL映射將用戶的HTTP訪問和該函數綁定起來,在app/目錄下建立一個urls.py文件,其文件的內容以下:
from django.contrib import adminfrom django.conf.urls import url from .apps import views urlpatterns = [ url(r'',views.welcome), #url(r'',views.welcome), ]
(3)在項目djangotest/urls.py文件中的urlpatterns中新增長一項,聲明對應用app中的urls.py文件的引用,具體代碼以下
from django.contrib import admin from django.urls import url from django.conf.urls import include urlpatterns = [ url('admin/', admin.site.urls),
url(r'app/', include('app.urls')),
]
首先導入django.conf.urls.include()函數,以後再urlpatterns列表中增長一個路徑app/,將其轉接到app.urls包,這樣經過include()函數就能夠將2個urlpatterns鏈接起來。
(4)上述代碼書寫完成後,輸入python manage.py runserver 127.0.0.0:8888。命令開啓web服務,在瀏覽其中輸入網址http://127.0.0.0:8888/app,結果以下圖所示。
這一節介紹的是Model層的處理,設計和開發信息發佈的數據訪問層。
要在django項目的setting.py文件中告訴django須要安裝應用app中的模型,方法是在setting.py文件中的INSTALLED_APPS數據結構中,在其中添加應用app的 config類,代碼以下:
INSTALLED_APPS = [ 'app', # 新增 ]
打開app/models.py文件,在其中新建一個模型類Mount,用來定義信息發佈表,代碼以下:
from django.db import models class Mount(models.Model): content = models.CharField(max_length=200) username = models.CharField(max_length=20) kind = models.CharField(max_length=20)
首先引入modoels類,全部的django模型類都是繼承於它。類Mount繼承了models類,在其中定義了3個字段content:消息的內容、username:發佈人名稱、kind:消息的類型。
django的術語「生成數據移植文件」是指將models.py中定義的數據錶轉換成數據庫生成腳本的過程。該過程經過命令行工具manage.py完成,具體的命令輸出以下:
經過輸出咱們能夠看到完成了模型Mount的創建。輸出中的0001_initial.py是數據庫生成的中間文件,經過它能夠知道當前數據庫的版本;該文件以及之後全部的migration文件都存儲於目錄migrations/中。
同時在makemigrations的過程當中,django會對比models.py中模型和已有數據庫之間的差別,沒有差別則不作操做,如再次執行makemigrations操做時將產生以下輸出:
可是若是對models.py文件做出修改時,則在下一次makemigrations的時候會將修改的內容同步到數據庫中。例如將kind字段修改成長度30後,執行操做,結果以下:
在該過程當中產生了新的中間文件0002_auto_20190526_1431.py。須要注意的是djangotest\app\migrations目錄中的文件都有manage.py本身維護,開發者不宜修改其中的內容。
在模型的修改過程當中能夠隨時調用makemigrations生成的中間移植文件。當須要真正的修改數據庫的時候,須要經過manage.py的migrate命令讓修改同步到數據庫。例如:
創建表單類文件djangotest/app/forms.py,在其中定義表單類MountForm,代碼以下:
from django.forms import ModelForm from models import Mount class MountForm(ModelForm): class Meta: model = Mount fields = '__all__'
爲了使用戶可以以單選的方式設置消息類型,則須要在models.py文件中定義單選的枚舉類型,而且與模型類Mount進行關聯。代碼以下:
from django.db import models # Create your models here. class Mount(models.Model): content = models.CharField(max_length=200) username = models.CharField(max_length=20,default='張曉琳') # 新增元祖用於設置消息枚舉類型 KIND_CHOICES = (('python','python'),('java','java'),('C語言','C語言'), ('C++', 'C++'), ('mysql', 'mysql'),) kind = models.CharField(max_length=30,choices=KIND_CHOICES,default=KIND_CHOICES[0])
模板文件是python web框架中用於產生HTML、XML等文本格式文檔的術語。模板文件自己也是一種文本文件,開發者須要手工進行編輯。創建目錄djangotest/app/templates,在其中新建模板文件moments_input.html,文件內容以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>消息錄入頁面</title> </head> <body> <form action="?" method="post"> <fieldset> <legend>請輸入並提交</legend> {{ form.as_p }} <input type="submit" value="提交" /> </fieldset> </form> </body> </html>
模板文件是html文件,其中的模板內容使用大括號進行標識。這裏使用{{ form.as_p }}定義表單類的輸入字段。
接下來開發的是視圖文件,使得表單類和頁面模板可以銜接起來。打開djangotest/app/views.py文件,在其中加入以下函數:
import os
from app.form import MountForm
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def moments_input(request):
if request.method == 'POST':
form = MountForm(request.POST)
if form.is_valid():
moment = form.save()
moment.save()
# return HttpResponseRedirect("app.views.welcome")
else:
form = MountForm()
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
return render(request,os.path.join(project_root,'app/templates'),'moments_input.html',{'form':form})
在urls.py文件中增長視圖函數的路由映射。
urlpatterns = [
url('admin/', admin.site.urls),
url(r'^app/', include('app.urls')),
]
訪問地址爲http://127.0.0.1:9999/app/moments_input。
站點分爲「內容發佈」和「公共訪問」兩部分,「內容發佈」的部分負責添加、修改、刪除內容,開發這些重複的功能是一件單調乏味、缺少創造力的工做。爲此,Django會根據定義的模型類徹底自動地生成管理模塊
python manage.py createsuperuser
,按提示輸入用戶名、郵箱、密碼
編輯settings.py文件,設置編碼、時區
LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai'
打開booktest/admin.py文件,註冊模型
from django.contrib import admin from models import BookInfo admin.site.register(BookInfo)
刷新管理頁面,能夠對BookInfo的數據進行增刪改查操做
問題:若是在str方法中返回中文,在修改和添加時會報ascii的錯誤
解決:在str()方法中,將字符串末尾添加「.encode('utf-8')」
Django提供了admin.ModelAdmin類
經過定義ModelAdmin的子類,來定義模型在Admin界面的顯示方式
class QuestionAdmin(admin.ModelAdmin): ... admin.site.register(Question, QuestionAdmin)
list_display = ['pk', 'btitle', 'bpub_date']
list_filter = ['btitle']
search_fields = ['btitle']
list_per_page = 10
fields = ['bpub_date', 'btitle']
fieldsets = [ ('basic',{'fields': ['btitle']}), ('more', {'fields': ['bpub_date']}), ]
對於HeroInfo模型類,有兩種註冊方式
按照BookInfor的註冊方式完成HeroInfo的註冊
接下來實現關聯註冊
from django.contrib import admin from models import BookInfo,HeroInfo class HeroInfoInline(admin.StackedInline): model = HeroInfo extra = 2 class BookInfoAdmin(admin.ModelAdmin): inlines = [HeroInfoInline] admin.site.register(BookInfo, BookInfoAdmin) 能夠將內嵌的方式改成表格 class HeroInfoInline(admin.TabularInline)
發佈性別的顯示不是一個直觀的結果,可使用方法進行封裝
def gender(self): if self.hgender: return '男' else: return '女' gender.short_description = '性別' 在admin註冊中使用gender代替hgender class HeroInfoAdmin(admin.ModelAdmin): list_display = ['id', 'hname', 'gender', 'hcontent']
Django模型層是Django框架自定義的一套獨特的ORM技術,經過上幾章節的總結學習,咱們已經大概瞭解了Django模型層的基本概念和開發流程。如今來學習模型層的技術細節和高級話題。
使用Django模型開發的首要任務就是定義模型類和類的屬性。每一個模型類均可以被映射爲數據庫中的一個表,類屬性被映射成爲數據字段,除此以外,數據庫中的主鍵、外鍵、約束等也能夠經過類屬性完成定義。
模型定義的的基本結構以下所示:
from django.db import models class ModelsName(models.Model): field1 = models.XXfield(...) field2 = models.XXfield(...) ... class Meta: db_table = ... other_metas = ...
屬性 |
屬性值 |
說明 |
abstract |
True or False |
標識本類是否爲抽象的基類 |
app_lable |
app_lable = 「myapp」 |
定義本類所屬的應用 |
db_table |
db_table=「mytable」 |
映射的數據庫表名稱 說明:若是Meta中不提供db_table字段,則django會爲模型自動生成數據庫表名,格式爲「應用名_模型名」。 |
db_tablespace |
無 |
映射的表空間名稱。表空間的概念只在某些數據庫中如oracle中存在,不存在表空間概念的數據庫將會忽略本字段。 |
Default_related_name |
無 |
定義本模型的反向關係引用名稱,默認和模型名一致。 |
get_latest_by |
無 |
定義按那個字段值排列得到模型的開始或者結束記錄,本屬性值一般指向一個日期或者整形的模型字段。 |
managed |
True or False |
定義django的manage.py命令行工具是否管理本模型。屬性默認設置爲TRUE。設置爲false時,須要手動維護數據庫表。 |
order_with_respect_to |
無 |
定義本模型能夠按照某種外鍵引用的關係排序。 |
ordering |
Ordering = [「username」「-pub_data」] |
本模型記錄的默認排序字段,能夠設置多個字段,默認爲升序排列。降序排列的話在字典前加上- |
default_permissions |
Add,change,delete |
模型的操做權限,默認如值所示。 |
proxy |
True or False |
本模型及全部繼承自本模型的子類是否爲代理模式。 |
required_db_features |
fequired_db_features =[「gis_enabled」] |
定義底層數據庫所必須具有的特性,如值所示只將本數據模型生成在知足gis_enabled特性的數據庫中 |
required_db_vendor |
SQLite、PostgreSQL、MySQL、Oracle |
定義底層數據庫的類型,若是定義了本屬性,則模型只能在其聲明的數據庫中維護。 |
unique_together |
unique_together = ((「user」,「pwd」)) |
用來設置不重複的的字段組合,必須惟一(能夠將多個字段作聯合惟一)。 |
index_together |
index_together=[ [「pun_data」,「deadline」]] |
定義聯合索引的字段,能夠定義多個。 |
verbose_name |
verbose_name = ‘資產管理’ |
定義一個易於理解和表述的單數形式的對象名稱。若是不設置該值,則Django將會使用該models的類名做爲它的對象表述名。 |
verbose_name_plural |
|
定義一個易於理解和表述的複數形式的對象名稱。 |
Django的普通字段是指模型類中除了外鍵之外的數據字段屬性。它爲Django使用模型的時候提供以下信息:
全部的數據字段的屬性必須繼承自抽象類django.db.models.Field,咱們能夠本身定義繼承自該類的數據字段,也可使用Django預約義的一系列數據字段,常見的Django預約義字段類型描述以下表所示。
字段 |
字段說明 |
AutoField |
一個自動遞增的整形字段,添加記錄時它會自動增加。AutoField字段一般充當數據表的主鍵;若是沒有添加,django會自動添加一個該字段。 |
BigIntegerField |
64位的整型字段 |
BinaryField |
二進制數據字段,經過bytes進行賦值 |
BooleanField |
布爾字段,對應<input type=「CheckBox」> |
CharField |
字符串字段,對應<input type=「text」> |
TextField |
大容量文本字段,對應<textarea> |
CommaSeparatedIntegerField |
存放逗號分隔的整數值,有特殊的表單驗證要求 |
DateField |
日期字段,相對應的HTML標籤是<input type=「text」>、JavaScript日曆和一個today快捷按鍵。可選參數:auto_now:保存時,設置爲當前時間;auto_now_add:首次建立時,保存爲當前時間。 |
DateTimeField |
相似於DateField,可是它卻支持時間的輸入。 |
DurationField |
存儲時間週期,用python的timedelta類型構建。 |
EmailField |
檢查Email合法性的CharField。 |
FileField |
文件上傳字段。在定義本字段是必須傳入參數upload_to,用於保存上傳下載文件的服務器文件系統的路徑。這個路徑必須包含strftime formatting,該格式將被上載文件的date/time替換 |
FilePathField |
按照目錄的規則限制選擇文件,定義本字段是必須傳入參數path,用以限定目錄。 |
FloatField |
浮點型字段。定義本字段時必須傳入參數max_digits和decimal_places,用於定義總位數和小數位數。 |
ImageField |
相似於 FileField,同時驗證上傳的對象是不是一個合法圖片,可選參數有2個:height_field和width_field,有這兩個參數,圖片按照規定的長和高進行存儲。 |
IntegerField |
保存一個整數 |
IPAddressField |
一個字符串形式的IP地址 |
NullBooleanField |
相似於BooleanField,可是多出了一個None選項 |
PhoneNumberField |
帶有美國風格的電話號碼校驗的CharField(格式爲XXX-XXX-XXXX) |
PositiveIntegerField |
只能輸入非負數的IntegerField |
SlugField |
只包含字母,數字,下劃線和連字符的輸入,一般同於URL |
SmallIntegerField |
相似於IntegerField,可是隻有較小的輸入範圍,依賴所使用的數據庫。 |
TimeField |
時間字段,相似於DateTimeField,但只能表達和輸入時間。 |
URLField |
用於保存URL |
USStateField |
美國州名的縮寫字段 |
XMLField |
XML字符字段,是具備XML合法性驗證的TextField |
|
|
每一個字段類型都有一些特定的HTML標籤和表單驗證參數,好比heigth_field,path等,但同時每一個字段都有能夠設置的公告方法,好比primary_key參數設置的主鍵字段。
from django.db import models class Comment(models.Model): # 設置主鍵id id = models.AutoField(primary_key=True)
from django.db import models class Comment(models.Model): # 設置主鍵id id = models.AutoField(primary_key=True) # 定義選擇元祖 levels = (('1','Very Good'),('2','Good'),('3','Normal'),('4','Bad')) level = models.CharField(max_length=10,choices=levels)
上述代碼中定義了level字段用於讓用戶選擇滿意度,其中的1,2,3,4是在數據庫中實際存儲的數據,而very good、Good、Normal、Bad等是在HTML頁面中供選擇的選項。
除了這些名稱的字段外,Django中的全部字段還有一個無名參數,能夠設置該字段在HTML頁面的顯示名稱,好比:
level = models.CharField('客戶滿意度選擇',max_length=10,choices=levels)
定義以下的Django models,用於演示Django的模型基本查詢技術。
from django.db import models class Comment(models.Model): # 設置主鍵id id = models.AutoField(primary_key=True) # 定義選擇元祖 levels = (('1','Very Good'),('2','Good'),('3','Normal'),('4','Bad')) level = models.CharField('客戶滿意度選擇',max_length=10,choices=levels) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateTimeField() n_visits = models.IntegerField() def __str__(self): return self.headline
(1) Django有2中過濾器用於對記錄進行刷選,以下:Django經過模型的objects對象查詢模型的數據,例以下面的語句查詢Comment模型的全部數據:Comment.objects.all()
(2)鏈接查詢
多個filter和exclude能夠連在一塊兒進行查詢,好比查詢全部2015年非1月的n_visits不爲0的記錄:Comment.objects.filter(pub_date_year == 2015).exclude(pub_date_month=1).exclude(n_visits_exact=0)。
咱們能夠看到代碼中的pub_date_year,它並非模型中定義的一個字段,而是Django定義的一種獨特的字段查詢方式,本例中該查詢的含義是「pub_date字段的year屬性爲2015」。基本的表現形式爲 字段名稱_謂詞,既由「雙下劃線鏈接的字段名稱和謂詞」來表達查詢條件。相似的還有不少其餘的謂詞查詢方式,完整的Django謂詞列表以下標所示。
謂詞 |
含義 |
示例 |
等價的sql語句 |
exact |
精確等於 |
Com.objects.filter(id_exact=14) |
Select * from Com where id = 14; |
iexact |
大小寫不敏感的等於 |
Com.objects.filter(headline_iexact=」I am ok」) |
Select * from Com where upper(headline)=」 I am ok」 |
contains |
模糊匹配 |
Com.objects.filter(headline_ contains =」good」) |
Select * from Com where headline like 」%good%」; |
in |
包含 |
Com.objects.filter(id_ in =[1,5,9]) |
Select * from Com where id in [1,5,9]; |
gt |
大於 |
Com.objects.filter(id_ gt=30) |
Select * from Com where id > 30; |
gte |
大於等於 |
||
lt |
小於 |
||
lte |
小於等於 |
||
startwith |
以..開頭 |
Com.objects.filter(body_text_ startwith=」wl」) text_ endwith=」wl」 |
Select * from Com where body_text like 」good%」 」%good」; |
endwith |
以..結尾 |
||
range |
在..範圍內 |
Com.objects.filter(pub_date_range=(starttime,endtime)) |
Select * from Com where pub_date between starttime and endtime; |
year |
年 |
Com.objects.filter(pub_date_year == 2015) |
Select * from Com where pub_date between 「2015-1-1 00:00:00」 and 「2015-12-31 23:59:59」; |
month |
月 |
||
day |
日 |
||
Week_day |
星期幾 |
||
isnull |
是否爲空 |
Com.objects.filter(pub_date_isnull = True) |
Select * from Com where pub_date is Null; |
(3)除了all()、filter()、exclude()等返回數據集的函數,Django還提供了get()函數用於查詢單挑記錄,好比查詢id爲3的記錄:
Com.objects.get(id_exact = 1)
(4)Django還提供了用於查詢指定條數的小標操做,該特性使得Django模型可以支持SQL中的limit和offset。
(5)Django還提供了order_by操做,示例以下:
Com.objects.order_by(「headline」):返回數據集,按照headline字段排序。
和傳統的sql相比,Django的一個較大的優點是定義了一個統一的方法save(),用於完成模型的insert和update操做。在執行模型的save()函數時,Django會根據模型的主鍵,判斷記錄是否存在,若是存在執行update操做,不存在執行insert操做。
# 新增記錄 obj = Comment(headline='i am ok',body_text='...sdjk', pub_date = datetime.datetime().now(),n_visits=0) obj.save() print(obj.id) # 打印主鍵id22 # 修改記錄數據 obj.body_text = "this is my world, I am god!!" obj.save() print(obj.id) # 打印主鍵id=22,和新增後的id相同。
4.2.3 數據刪除
Django模型提供了delete()方法用於刪除記錄,該方法能夠進行單條和批量刪除。示例代碼以下:
# 刪除id爲3的記錄 Comment.objects.get(id=3).delete() # 刪除2015年全部的記錄 Comment.objects.filter(pub_date_year = 2015).delete()
利用數據表之間的關係進行數據建模和業務開發是關係型數據庫最主要的功能。Django的模型層對這三種關係模型(1:1,1:N;M:N)都有強大的支持。
在SQL語言中,一對一的關係經過在兩個表之間定義相同的主鍵來完成。在Django的模型層,能夠在任意一個模型中定義OneToOneField字段,而且定義相互之間的一對一關係。以下的代碼在模型Account和Contact之間定義了一對一的關係。
class Account(models.Model): user_name = models.CharField(max_length=80) password = models.CharField(max_length=255) reg_date = models.DateTimeField() def __str__(self): return "Account:%s" % self.user_name class Contact(models.Model): account = models.OneToOneField(Account,on_delete=models.CASCADE,primary_key=True) zip_code = models.CharField(max_length=10) address = models.CharField(max_length=80) mobile = models.CharField(max_length=20) def __str__(self): return "%s,%s" % (self.account.user_name,self.mobile)
在上述一對一的關係模型中的開發代碼以下所示。
a1 = Account(user_name='wltest') a1.save() # 保存一個Account記錄 print(a1) # 打印a1:<Account:wltest> a2 = Account(user_name='zxlText') a2.save() # 保存一個Account記錄 # 利用a1初始化Contact的account字段,並保存 a3 = Contact(account=a1,mobile='1223123123') a3.save() print(a3) # <Contact:wltest,1223123123> print(a1.contact) # <Contact:wltest,1223123123>,經過關係打印,於打印a3的結果相同 print(a3.account) # <account:wltest>,經過關係打印,於打印a1的結果相同 # a2沒有和Contact創建過關係,因此沒有contact字段。 a1.delete() # on_delete = models.CASCADE,因此刪除a1時也刪除了a3
在SQL語言中,1:N關係經過在「附表」中設置「主表」的外鍵引用來完成。在Django模型層,可使用models.ForeignKey()來定義外鍵,代碼以下:
from django.db import models class Account(models.Model): user_name = models.CharField(max_length=80) password = models.CharField(max_length=255) reg_date = models.DateTimeField() def __str__(self): return "Account:%s" % self.user_name class Contact(models.Model): # account = models.OneToOneField(Account,on_delete=models.CASCADE,primary_key=True) account = models.ForeignKey(Account, on_delete=models.CASCADE) zip_code = models.CharField(max_length=10) address = models.CharField(max_length=80) mobile = models.CharField(max_length=20) def __str__(self): return "%s,%s" % (self.account.user_name,self.mobile)
上述代碼於一對一關係惟一不一樣的地方在於models.ForeignKey定義了Contact模型中的account字段。這樣一來,每一個Account對象就能夠與多個Contact對象關聯了。模型的使用代碼以下:
def welcome(request): a1 = Account(user_name='wl2',password='12343') a1.save() # 保存一條Account記錄 # 爲a1創建兩個Contact關聯的對象 c1 = Contact(account=a1,address='c1',mobile='12312321412') c1.save() # 保存C1記錄 c2 = Contact(account=a1, address='c2', mobile='12312321412') c2.save() # 保存C2記錄 data = {c1.address:str(c1.account), c2.address:str(c2.account),'a1':str([a1.contact_set,a1.contact_set.count()])} a1.delete() return JsonResponse({'status':200,'data':data})
在一對多關係中,每一個主模型對象能夠關聯多個子對象,因此本例中從主模型Account對象尋找附屬模型Contact的屬性時contact_set,經過一個集合返回關聯結果。
說明:XXX_set是Django設定的經過主模型對象訪問附屬模型的對象集合的屬性名。
在SQL語言中,M:N關係經過創建一箇中間關係表來實現,該中間表中定義了到2個主表的外鍵。因此在Django模型層中,開發者也能夠選擇用這兩個1:N關係來定義M:N的關係。這種方式是經過models.ForeignKey來實現。
另一種方式是在django的模型層中定義一個models.ManyToManyField字段來實現的,多對多關係的模型定義代碼以下:
from django.db import models class Account(models.Model): user_name = models.CharField(max_length=80) password = models.CharField(max_length=255) # reg_date = models.DateTimeField() def __str__(self): return "Account:%s" % self.user_name class Contact(models.Model): account = models.ManyToManyField(Account) zip_code = models.CharField(max_length=10) address = models.CharField(max_length=80) mobile = models.CharField(max_length=20) def __str__(self): return "%s,%s" % (self.account.user_name,self.mobile)
上述代碼經過在Contact中定義引用Account的ManyToManyField,實現了2個模型的多對多關聯,對此模型的定義操做演示以下:
# 分別創建並保存Account和Contact的對象 a1 = Account(user_name='ww') a1.save() c1 = Contact(mobile='weeee3') c1.save() # t經過Contact對象創建關係 c1.account.add(a1) a2 = Account(user_name='jjj') a2.save() a2.contact_set.add(c1) # 經過Account對象創建關係 a3 = Account(user_name='jjj') # 對象未保存出錯 a3.contact_set.add(c1) # 經過Account對象創建關係 a1.contact_set.remove() # 取消單個對象的關聯 a1.contact_set.clear() # 取消全部對象的關聯
Django模型層ORM的一個強大之處是對模型繼承的支持,該技術將python面向對象的編程方法與數據庫面向關係表的數據有機的結合。支持三種風格的模型集成。相面來介紹這三種繼承方法。
抽象類繼承是指父類繼承models.Model,但不會在底層的數據庫中生成相應的數據表,父類的相關屬性字段存儲在子類的數據表中。
它的做用是在多個表有想幹的字段時,可使得開發者將這些字段統必定義在抽象基類中,免於重複定義這些字段。抽象基類的定義經過在模型的Meta中定義屬性abstract=True來實現,示例代碼以下:
class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user = models.CharField(max_length=20) pub_date = models.DateTimeField() class Meta: # 定義本類爲抽象基類 abstract = True class Mon(MessageBase): headline = models.CharField(max_length=50) class Com(MessageBase): life = models.CharField(max_length=30,default='wl',choices=(('1','2'),('sjdk','idi')))
在子類模型的編程中,能夠直接使用父類定義的字段,例如:上述代碼中定義了一個抽象基類MessageBase,用於保存消息的4個字段。子類Mom和Com繼承自MessageBase,並分別定義了本身的一個字段。這3個類映射到數據後,會別定義成2個數據庫表。每一個表都有5個字段
m1 = Mon(user='ds',headline='sds') m1.content = 'sddhjk' m1.save()
多表繼承的模型類都在底層的數據庫中生成了相應的數據表管理數據。不管是父表仍是子表都會用數據庫中相對應的數據表維護模型的數據,父類中的字段不會重複的在多個子表中進行定義。從這方面來說,多表繼承纔是真正面向對象的ORM技術。
多表繼承不須要特殊的關鍵字。在Django內部經過在父類和子類之間創建一對一關係來實現多表繼承,示例代碼以下。
from django.db import models class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user = models.CharField(max_length=20) pub_date = models.DateTimeField() class Mon(MessageBase): headline = models.CharField(max_length=50) class Com(MessageBase): life = models.CharField(max_length=30,default='wl',choices=(('1','2'),('sjdk','idi')))
仍然能夠直接引用父類定義的字段,同時子類能夠經過父類對象引用訪問父類的示例。上述代碼在數據庫中會實際生成3個數據表。同時在對模型的編程過程當中,子類
# 新建Mon對象,直接在子類中引用父類字段 m1 = Mon(user='ds',headline='sds') m1.content = 'sddhjk' m1.save() # 經過父類引用父類字段 print(m1.messagebase.content)
4.4.3 代理繼承
代理模型繼承指父類用於在底層數據庫中管理數據表,而子類不定義數據列。只定義查詢數據集的排序方式等元數據。前兩種繼承模型中都有實際存儲數據的做用,而代理模式繼承中子類只用於管理父類的數據,而不實際存儲數據。設置的方法是在Meta中定義proxy=True屬性來實現,示例代碼以下:
class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user = models.CharField(max_length=20) pub_date = models.DateTimeField() class Mon(MessageBase): class Meta: proxy = True ordering = ["-pub_date"]
Django視圖層的主要做用是銜接HTML模板、python程序、HTTP請求等。
URL分發映射配置能夠被看作Django項目的入口配置,經過URL分發能夠指定用戶的每個訪問的後臺python處理函數是什麼。
每個django項目都有一個urls.py文件用於維護自身的URL dispatcher,該文件的基本內容以下:
from django.contrib import admin from django.urls import path from django.conf.urls import url from . import views urlpatterns = [ url(r'^welcome',views.welcome), url(r'^moments_input/',views.moments_input), ]
程序經過維護urlpatterns列表中的元素完成URL的映射,每一個元素都是一個django.conf.urls.url的實例,函數url()的第1個參數是HTTP路徑,第2個參數是該路徑映射到的python函數名。
正則表達式速查表
符號 |
說明 |
例子 |
\ |
將下一個字符標記爲特殊字符 |
「\n」匹配一個換行符 「\\」匹配一個「\」 「\(」匹配一個「(」 |
^ |
字符串的開始位置 |
「^abc」:以abc開頭 |
$ |
字符串的結束位置 |
「abc$」:以abc結尾 |
* |
前面的子表達式0或者屢次 |
「2*」匹配「」「2」「2222」等 |
+ |
前面的子表達式1或者屢次 |
「2+」匹配「1」「2」「222」等 |
? |
前面的子表達式0或者1次 |
「3?」匹配「」或者「3」 |
. |
除\n之外的任意單個字符 |
|
{n} |
匹配n次 |
「o{2}」:匹配food中的兩個o |
{n,} |
至少匹配n次 |
|
{n,m} |
匹配n到m次 |
|
x|y |
匹配x或者y |
Asd|sdf:匹配Asd或者sdf |
[xyz] |
匹配xyz中任一字符 |
[123]匹配1,2或者3 |
[a-z] |
匹配a-z範圍內的字符 |
|
[^a-z] |
匹配不在a-z範圍內的字符 |
|
5.1.3 命名URL映射
在普通的URL映射中,Django將URL中的變量參數按照路徑中的出現順序傳遞給被調用函數。而命名URL參數映射使得開發者能夠定義這些被傳遞參數的名稱,命名URL參數的定義方式爲 ?p<param_name>pattern,示例代碼以下:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^year/2015/$',views.year2015), url(r'^year/?p<year>([0-9]{4})/$',views.year), url(r'^year/?p<year>([0-9]{4})/?p<month>([0-9]{2})/$',views.month), ]
上述代碼中的後兩個url()使用命名參數進行了定義,他們調用Views.py文件中的相關函數,調用的方式爲year(request,year=xxxx)和month(request,year=xxxx,month=xx)。
當多個URL映射到一個地址是,只選擇第一個映射。
在實際的大型項目開發中,一個項目可能包含多個Django應用,而每個都有本身的URL映射規則。這個時候講全部的URL映射都保存在一個文件中很是不利於對項目進行維護,因此Django提供了include()函數來進行分佈式的URL映射。在項目djangotest/djangotest/urls/py的文件中引用其餘應用的URL映射文件的代碼以下:
from django.contrib import admin from django.urls import path from django.conf.urls import include,url urlpatterns = [ url('admin/', admin.site.urls), url(r'^app/', include('app.urls')), ]
5.1.5 反向URL映射
除了以上介紹的幾種映射方式,Django還提供了反向的從映射名到URL地址的解析功能。URL反向解析使得開發者能夠用映射名代替不少須要寫絕對URL路徑的地方,提升了代碼的可維護性。
待續。。。很是重要
視圖函數是Django開發者處理HTTP請求的python函數。在一般的狀況下,視圖函數的功能是經過模型層對象處理數據,而後用以下所示的一種方式返回數據。
對於如下簡單的頁面,能夠直接在視圖函數中構造返回給客戶端的字符串,該功能是經過HttpResponse()函數封裝返回。
from django.http import HttpResponse def index(request): HttpResponse('<h2>我是你爸爸!</h2>')
from django.shortcuts import render def index(request): render(request,'index.html')
render()函數的第一個參數是HTTP Request,第二個參數是模板文件名,第三個參數是想模板文件中返回的數據,是字典的形式。
5.2.3 返回HTTP錯誤
HTTP的錯誤經過HTTP頭中的status來進行表述,經過給httpResponse函數傳遞status參數能夠返回HTTP的錯誤或者狀態。如:
from django.http import HttpResponseRedirect,HttpResponse def index(request): HttpResponse(status=404)
經過上述的代碼能夠返回HTTP 404錯誤。可是爲了方便開發者的使用,Django對經常使用的status狀態進行了進一步的封裝,具體的實現以下所示:
模板文件是一種文本文件,主要又目標文件的內容組成,而後輔以模板的特殊語法用於替換動態內容。下面的代碼是一個功能較爲齊全的模板文件。
{% extend "base.html" %} # 繼承基類模板 {% block title %}title 內容{% endblock %} {% block content %} <h1>{{ section.title }}</h1> {% for i in ins %} <h3> {{ i.code | upper }} </h3> {% endfor %} {% endblock %}
{% for moment in moments %} <h3> {{ moment.user | upper }} </h3> {% endfor %} {% if moment.id < 10 %} <h3>{{ moment.headline }}</h3> {% elif moment.id < 20 %} <h3>{{ moment.headline }}</h3> {% else %} <h3>{{ moment.headline }}</h3> {% endif %}
過濾器在模板中是放在變量後面用於對變量顯示的結果進行控制的技術,變量和過濾器之間用管道符號進行鏈接。具體的過濾器以下圖所示。
過濾器 |
說明 |