Django
1. 特點
- 快速開發(fā):Django的宗旨在于幫助開發(fā)人員快速從概念到完成應(yīng)用程序诲锹。
- 安全可靠:Django認真對待安全性按声,幫助開發(fā)人員避免許多常見的安全錯誤拓型。
- 超可伸縮性: Web上的一些最繁忙的網(wǎng)站利用了Django快速靈活擴展的能力如失。
2. 入門
MVC 設(shè)計模式
目標:程序的解耦
在行業(yè)內(nèi)普遍存在的設(shè)計模式
M ==> Model 模型 ==> 數(shù)據(jù)層 ==> 針對數(shù)據(jù)的操作 ===>轉(zhuǎn)化成對數(shù)據(jù)庫的操作 (sql) 映射關(guān)系
V ==> view 視圖 ==> 展示層 ==> 展示頁面(頁面中會有數(shù)據(jù)) 里面加載的是 模板(html文件)
C ==> Controller 控制器 ==> 邏輯層 ==> 業(yè)務(wù)邏輯 根據(jù)用戶的請求去調(diào)用模型,獲取數(shù)據(jù)后交給視圖去展示數(shù)據(jù)
MVT 設(shè)計模式
目標:程序的解耦
僅限于Django中的設(shè)計模式
M ==> Model 模型(對數(shù)據(jù)的操作)
V ==> view 視圖(業(yè)務(wù)邏輯)
T ==> Template 模板(頁面的展示)
路由
負責(zé)請求地址的匹配,并交給指定的視圖函數(shù)進行處理
如:www.pyweb.com/yichuan/p/123457/
前面到com都為域名策彤,后面的yichuan/p/123457/這是就是url地址
在路由的url函數(shù)中可以寫正則表達式進行匹配,例如:
url(r'^address/2003/$', views.year)
3. 項目的搭建
- 執(zhí)行命令:
django-admin startproject 項目名
- 系統(tǒng)會創(chuàng)建一系列文件和文件夾匣摘,其中項目名下有一個文件夾與項目同名
- 項目的總目錄可以重命名店诗,但是其中的文件盡量不要重命名,否則需要修改配置
創(chuàng)建應(yīng)用
- 命令行:
python3 manage.py startapp 應(yīng)用名
- 我們需要操作的文件
views.py
和models.py
啟動項目 ???
- 在終端中輸入命令行:
python3 manage.py runserver
- 之后終端中會返回地址音榜,一般都為本地地址:
http://127.0.0.1:8000
輸出一個 Hello World 的過程
- 創(chuàng)建應(yīng)用:
python3 manage.py startapp myhome
- 在應(yīng)用文件夾中找到視圖函數(shù)
views.py
- 定義視圖函數(shù)
def hello(request):
return HttpResponse('hello world')
注意:需要導(dǎo)入 HttpResponse:
from django.http import HttpResponse
-
定義路由規(guī)則
- 先到根路由urls.py文件中定義規(guī)則庞瘸,交給自定義應(yīng)用的子路由
url(r'^', include('myhome.urls'))
- 定義子路由器,在自定義應(yīng)用中創(chuàng)建一個urls.py文件,并添加路由規(guī)則
url(r'^', views.hello)
,其中url函數(shù)三個參數(shù)赠叼,第一個為路由規(guī)則擦囊,第二個為指定的視圖函數(shù)
- 先到根路由urls.py文件中定義規(guī)則庞瘸,交給自定義應(yīng)用的子路由
啟動服務(wù)违霞,開始訪問
請求、訪問過程
1. 當(dāng)用戶在瀏覽器中訪問url地址時瞬场,服務(wù)器接收請求
2. --> 交給根路由進行匹配
3. --> 交給子路由進行url地址匹配
4. --> 子路由調(diào)用相應(yīng)的視圖函數(shù)
5. --> 視圖函數(shù)進行執(zhí)行买鸽,開始響應(yīng)
4. 使用模板
-
配置模板引擎
- 找到項目配置文件 settings.py
- 修改templates的配置項中的DIRS為:
'DIRS':[os.path.join(BASE_DIR,'templates')]
在manage.py文件的同級目錄下創(chuàng)建一個templates的文件夾,里面放置模板文件,即html文件
在視圖函數(shù)中使用render函數(shù)加載模板
def tmp(request):
return render(request,'t.html')
# 其中render函數(shù)有三個參數(shù)贯被,1-請求對象眼五,為固定寫法;2-模板路徑彤灶;3-傳入模板的數(shù)據(jù)(字典類型)
5. 路由規(guī)則 ???
基本規(guī)則
- 路由按照從上至下的順序執(zhí)行
- 路由中可以使用()來捕獲 url 請求中的一部分作為參數(shù)來使用看幼,例如
# 請求路徑:http://127.0.0.1:9000/articles/2014/
# 路由規(guī)則
url(r'^articles/([0-9]{4})/$', views.year_archive),
# 視圖函數(shù)
def year_archive(request,y):
print(y)
return HttpResponse('year_archive')
注意:在有()的正則路由規(guī)則中,對應(yīng)的視圖函數(shù)中必須用形參來接收()中的傳入的參數(shù)
正則表達式命名組
以上的路由規(guī)則中幌陕,對視圖函數(shù)的接收沒有命名要求诵姜,形參的名字可以隨意更改,但是命名組規(guī)則要求視圖函數(shù)中接收參數(shù)的形參必須為規(guī)定的名稱苞轿,例如
# 路由規(guī)則
url(r'^abc/(?P<year>[0-9]{4})/$', views.abc_2003),
# 視圖函數(shù)
def abc_2003(request,year):
print(year)
return HttpResponse('abc_2003')
默認值參數(shù)
使用兩個路由規(guī)則茅诱,指向同一個視圖函數(shù)
# 路由規(guī)則
url(r'^user/list/$', views.userlist),
url(r'^user/list/(?P<page>[0-9]+)/$', views.userlist),
# 視圖函數(shù)
def userlist(request,page=1):
print(page)
return HttpResponse('userlist')
url的反向解析 ?????
通過路由規(guī)則的名(name),動態(tài)解析路由的地址
如果在視圖搬卒、模板中使用硬編碼(直接寫死請求地址)的鏈接瑟俭,在你url發(fā)生改變時,維護是意見非常麻煩的事情
# 為了能夠動態(tài)的解析url的規(guī)則契邀,可以在定義路由規(guī)則時摆寄,給路由器起一個名字(name)
# 路由規(guī)則
url(r'^goods/list/$', views.goodslist,name='glist'),
# 然后可以在視圖和模板中通過反向解析動態(tài)的獲取路由解析地址
# 視圖函數(shù)
def hello(request):
# 視圖函數(shù)中進行反向解析,獲取url地址坯门,需要提前導(dǎo)入reverse
# from django.core.urlresolvers import reverse
r1 = reverse('goods')
r2 = reverse('order')
print(r1,r2)
return render(request, 't.html')
# 模板
<a href="{% url 'glist' %}">商品列表:反向解析格式</a>
注意:路由規(guī)則中如果有參數(shù)要求微饥,那么模板中在使用url進行反向解析時,必須給參數(shù)
<a href="{% url 'olist' 100 %}">訂單列表:反向解析格式</a>
反向解析是路由中的重中之重古戴,必須要搞清楚欠橘!
6. 模型關(guān)系 ????
一對一(人對應(yīng)身份證)
定義
一對一關(guān)系指模型的關(guān)系時一一對應(yīng)的,例如:
- 一個用戶對應(yīng)一條用戶詳細信息
- 一個身份證對應(yīng)一個人
- 一個微信號對應(yīng)一個用戶
二者一一對應(yīng),如果有一個用戶的詳細信息,必對應(yīng)一個用戶
創(chuàng)建模型
- 在建立模型時建立兩個模型,在其中一個模型中加入外鍵
- 在模型中使用
models.OneToOneField(關(guān)聯(lián)的模型名,是否關(guān)聯(lián)刪除)
來建立外鍵,沒有外鍵的為主數(shù)據(jù),有外鍵的為副數(shù)據(jù)
# 模型關(guān)系 一對一
# 用戶模型
class User(models.Model):
username = models.CharField(max_length=50)
age = models.IntegerField()
# 用戶詳情
class UserInfo(models.Model):
# 此語句為創(chuàng)建外鍵
uid = models.OneToOneField(User,on_delete=models.CASCADE)
xueli = models.CharField(max_length=50)
yuanxiao = models.CharField(max_length=5)
增刪查
-
增加
一對一模型進行增加時不需要特殊注意,直接進行增加,Django框架會自動將兩個模型創(chuàng)建的數(shù)據(jù)進行關(guān)聯(lián) -
刪除
一對一模型在進行數(shù)據(jù)刪除時,如果刪除的是主數(shù)據(jù),則副數(shù)據(jù)也會被刪除;如果副數(shù)據(jù)被刪除,主數(shù)據(jù)則不會被刪除 -
查詢
一對一模型在進行數(shù)據(jù)查詢時有兩種方法:- 通過主數(shù)據(jù)查找副數(shù)據(jù):
主數(shù)據(jù)對象.副數(shù)據(jù)類名(小寫).查詢的屬性名
- 通過副數(shù)據(jù)查找主數(shù)據(jù):
副數(shù)據(jù)對象.外鍵名.查詢的屬性名
- 通過主數(shù)據(jù)查找副數(shù)據(jù):
# 模型關(guān)系:一對一
def one(request):
# 添加
# # 創(chuàng)建用戶
data = {'username':'燕小六','age':20}
user = User.objects.create(**data)
# 創(chuàng)建詳情
infodata = {'uid':user,'xueli':'本科','yuanxiao':'家里蹲'}
info = UserInfo.objects.create(**infodata)
# 刪除
# 刪除用戶時會關(guān)聯(lián)刪除對應(yīng)的詳情數(shù)據(jù)
user = User.objects.first()
user.delete()
# 刪除詳細信息,用戶不會被刪除
ui = UserInfo.objects.first()
ui.delete()
# 查詢
# 根據(jù)用戶獲取詳細信息
user = User.objects.first()
print(user.username)
print(user.userinfo.xueli)
# # 根據(jù)詳細信息獲取用戶信息
ui = UserInfo.objects.first()
print(ui.xueli)
print(ui.uid.username)
return HttpResponse('<h1>模型關(guān)系:一對一<h1>')
一對多(商品分類對應(yīng)分類下的商品) ????
定義
- 一個商品分類對應(yīng)多個商品
- 一個班級對應(yīng)多個學(xué)生
- 一個國家對應(yīng)多個城市
創(chuàng)建模型
- 在建立模型時建立兩個模型,在商品中加入外鍵
- 在模型中使用
models.ForeignKey(關(guān)聯(lián)的模型名)
來建立外鍵
# 模型關(guān)系:一對多
# 商品類別
class Classify(models.Model):
name = models.CharField(max_length=50)
# 商品
class Goods(models.Model):
# 設(shè)置外鍵,第二個參數(shù)為可選
cid = models.ForeignKey(to="Classify", to_field="id")
title = models.CharField(max_length=50)
price = models.IntegerField()
def __str__(self):
return self.title
增刪查
-
增加
增加時不需要特殊注意,直接進行增加,Django框架會自動將兩個模型創(chuàng)建的數(shù)據(jù)進行關(guān)聯(lián) -
刪除
如果刪除的是商品分類,則分類下的商品也會被刪除;如果分類下的商品被刪除,商品分類則不會被刪除 -
查詢
一對一模型在進行數(shù)據(jù)查詢時有兩種方法:- 獲取商品分類下所有商品:
商品分類.商品類名(小寫)_set.all()
- 獲取商品所屬分類:
商品對象.外鍵名.查找的屬性
- 獲取商品分類下所有商品:
# 模型關(guān)系:一對多
def two(request):
# 添加
# 創(chuàng)建商品分類
c = Classify.objects.create(**{'name':'手機'})
# 創(chuàng)建商品
g1 = Goods.objects.create(**{'cid':c,'title':'小米8','price':'2399'})
g1 = Goods.objects.create(**{'cid':c,'title':'華為P20','price':'4399'})
g1 = Goods.objects.create(**{'cid':c,'title':'OPPO Find X','price':'4999'})
# 刪除
c = Classify.objects.last()
c.delete()
# 查詢
# 根據(jù)分類獲取下面所有的商品
c = Classify.objects.first()
print(c.name)
print(c.goods_set.all())
# 根據(jù)商品獲取其分類
g = Goods.objects.first()
print(g.title)
print(g.cid.name)
return HttpResponse('模型關(guān)系:一對多')
多對多(一本書對應(yīng)多個標簽,一個標簽對應(yīng)多本書) ????
定義
- 一本書對應(yīng)多個標簽,一個標簽對應(yīng)多本書
- 一個老師對應(yīng)多個班級,一個班級對應(yīng)多個老師
創(chuàng)建模型
- 需要用到第三張表,而不是單單在表中添加外鍵
- 第三張表用來記錄書和標簽互相的關(guān)系
- 在模型中使用
models.ManyToManyField(關(guān)聯(lián)的模型名)
來建立對多對關(guān)系,且定義在任意模型中即可
# 模型關(guān)系:多對多
# 書
class Books(models.Model):
title = models.CharField(max_length=50)
def __str__(self):
return self.title
class Tags(models.Model):
name = models.CharField(max_length=50)
# 設(shè)置關(guān)系語句
bid = models.ManyToManyField(to="Books")
def __str__(self):
return self.name
增刪查
-
增加
增加時需要進行關(guān)系聲明,且方式取決于關(guān)系語句設(shè)置在哪個模板中,以上面代碼為例- 給書添加標簽:
書對象.tags_set.set([標簽對象1,標簽對象2,...])
- 給標簽添加書:
標簽對象.bid.add(書對象1,書對象2,...)
- 多對多關(guān)系設(shè)置方法:
- .set([對象1,對象2,...]) 添加關(guān)系
- .add(對象1,對象2,...) 添加關(guān)系
- .clear() 清空關(guān)系
- 給書添加標簽:
-
刪除
- 無論刪除書或標簽,表3中相應(yīng)的關(guān)系記錄都會關(guān)聯(lián)刪除
- .clear() 清空指定對象的所有關(guān)系
-
查詢
- 獲取一本書的所有標簽:
書對象.tags_set.all()
- 獲取一個標簽下的所有書:
標簽對象.bid.all()
- 獲取一本書的所有標簽:
7. 模型查詢
1. 查詢集
- 在管理器上調(diào)用過濾器方法會返回查詢集,查詢集表示從數(shù)據(jù)庫中獲取的對象集合
- 查詢集經(jīng)過過濾器篩選后返回新的查詢集,因此可以寫成鏈式過濾
- 惰性執(zhí)行:創(chuàng)建查詢集不會帶來任何數(shù)據(jù)庫的訪問现恼,直到調(diào)用數(shù)據(jù)時肃续,才會訪問數(shù)據(jù)庫
- 何時對查詢集求值:迭代,序列化叉袍,與if合用
- 返回查詢集的方法始锚,稱為過濾器
- all(): 獲取所有的返回值
- filter(): 過濾掉不符合條件的值
filter(鍵1=值1,鍵2=值2)
==filter(鍵1=值1).filter(鍵2=值2)
- exclude(): 獲取除了滿足條件之外的值
- order_by(): 分組返回值根據(jù)條件進行排序
- values(): 一個對象構(gòu)成一個字典,然后構(gòu)成一個列表返回
返回單個值
- get(): 返回單個滿足條件的對象
- 如果未找到則引發(fā)
模型類.DoesNotExist
異常 - 如果返回多條,會引發(fā)"模型類.MultipleObjectsReturned"異常
- 如果未找到則引發(fā)
- count(): 返回當(dāng)前查詢的總條數(shù)
- first(): 返回第一個對象
- last(): 返回最后一個對象
- exists(): 判斷查詢集中是否有數(shù)據(jù),如果有返回True,反之返回False
限制查詢集
- 查詢集返回列表喳逛,可以使用下標的方式進行限制瞧捌,等同于sql中的limit和offset子句
- 注意:不支持負數(shù)索引
- 使用下標后返回一個新的查詢集,不會立即執(zhí)行查詢
- 如果獲取一個對象,直接使用[0]姐呐,等同于[0:1].get()殿怜,但是如果沒有數(shù)據(jù),[0]引發(fā)IndexError異常皮钠,[0:1].get()引發(fā)DoesNotExist異常
#這會返回前5個對象 LIMIT 5
Entry.objects.all()[:5]
#這將返回第六個到第十個對象 OFFSET 5 LIMIT 5
Entry.objects.all()[5:10]
2. 字段查詢
- 實現(xiàn)where子名稳捆,作為方法filter()、exclude()麦轰、get()的參數(shù)
- 語法:屬性名稱__比較運算符=值
- 表示兩個下劃線乔夯,左側(cè)是屬性名稱,右側(cè)是比較類型
- 對于外鍵款侵,使用“屬性名_id”表示外鍵的原始值
- 轉(zhuǎn)義:like語句中使用了%與末荐,匹配數(shù)據(jù)中的%與,在過濾器中直接寫新锈,例如:filter(title__contains="%")=>where title like '%%%'甲脏,表示查找標題中包含%的
比較運算符
- exact:判斷等,區(qū)分大小寫;如果沒有寫'比較運算符',表示判斷等
filter(isDelete=False)
- contains:是否包含,區(qū)分大小寫
exclude(btitle__contains='傳')
- startwith\endswith:以value開頭或結(jié)尾,區(qū)分大小寫
exclude(btitle__endswith='傳')
- isnull\isnotnull:判斷是否為null
filter(btitle__isnull=False)
在前面加個i表示不區(qū)分大小寫,如iexact妹笆、icontains块请、istarswith、iendswith
in:是否包含在范圍內(nèi)
filter(pk__in=[1, 2, 3, 4, 5])
- gt拳缠、gte墩新、lt、lte:大于窟坐、大于等于海渊、小于、小于等于
filter(id__gt=3)
- year哲鸳、month臣疑、day、week_day徙菠、hour讯沈、minute、second:對日期間類型的屬性進行運算
filter(bpub_date__year=1980)
filter(bpub_date__gt=date(1980, 12, 31))
8.View視圖
1. GET\POST
一鍵一值
# 這種方式當(dāng)鍵不存在或多個鍵時會報錯
request.GET['name']
# 這種方式None為默認值,如果數(shù)據(jù)不存在則返回默認值
request.GET.get('name',None)
request.POST['name']
request.POST.get('name',None)
一鍵多值
# 返回值為一個列表
request.GET.getlist('name',None)
request.POST.getlist('name',None)
2. HttpResponse對象
- 在django.http模塊中定義了HttpResponse對象的API
- HttpRequest對象由Django自動創(chuàng)建婿奔,HttpResponse對象由程序員創(chuàng)建
- 在每一個視圖函數(shù)中必須返回一個HttpResponse對象,當(dāng)然也可以是HttpResponse子對象
3. HttpResponse
- 不使用模板,直接返回數(shù)據(jù)
- 返回數(shù)據(jù)類型為字符串
- 如果字符串中是標簽,瀏覽器可以進行解析
return HttoResponse('你好')
4. render
- 調(diào)用模板返回數(shù)據(jù)
- 參數(shù)1:request,固定形式
- 參數(shù)2:'模板路徑',即html文件的路徑
- 參數(shù)3:字典類型的數(shù)據(jù),用于傳入模板中
return render(request,'user/edit.html',{'info':'你好'})
5. 子類 HttpResponseRedirect
- 重定向缺狠,服務(wù)器端跳轉(zhuǎn)
- 構(gòu)造函數(shù)的第一個參數(shù)用來指定重定向的地址
- 可以簡寫為 redirect
return redirect(reverse('myindex')
6. 子類 JsonResponse
- 返回json書,一般用于異步請求
- 幫助用戶創(chuàng)建JSON編碼的響應(yīng)
- JsonResponse的默認類型為application/json
- 參數(shù)1:字典類型數(shù)據(jù)
- 參數(shù)2:safe=True/False,默認為True,False表示關(guān)閉數(shù)據(jù)安全,參數(shù)1可以傳入非字典類型
return JsonResponse([{'list': 'abc'},{'d': 'ac'}],safe=False)
7. set_cookie 方法
- Cookie 是由 Web 服務(wù)器保存在用戶瀏覽器(客戶端)上的小文本文件,它可以包含有關(guān)用戶的信息脸秽。
- 服務(wù)器可以利用Cookies包含信息的任意性來篩選并經(jīng)常性維護這些信息,以判斷在HTTP傳輸中的狀態(tài)蝴乔。
- Cookies最典型的應(yīng)用是判定注冊用戶是否已經(jīng)登錄網(wǎng)站
- 設(shè)置cookie
# 設(shè)置cookie
def setcok(request):
# 獲取當(dāng)前的 響應(yīng)對象
res = HttpResponse('設(shè)置cookie')
# 使用響應(yīng)對象進行cookie的設(shè)置
res.set_cookie('a', 'abcd')
# 返回響應(yīng)對象
res.set_cookie('c', 'cdef')
return res
- 獲取cookie
# 獲取cookie
def getcok(request):
cok = request.COOKIES.get('a', None)
return HttpResponse(cok)
8. set_session 方法
- sesison方式所有數(shù)據(jù)存儲在服務(wù)器端记餐,在客戶端cookie中存儲唯一的身份標識
- 當(dāng)用戶進行請求時,判斷cookie中的唯一標識符是否與用戶請求中攜帶的唯一標識符相同
- 認證成功后頁面可以調(diào)用session中的所有內(nèi)容
- 向?qū)τ赾ookie更加安全,信息不容易被截獲
- 存儲的內(nèi)容比cookie更加豐富
- 開啟session
- 使用django-admin startproject創(chuàng)建的項目默認啟用
- 禁用會話:刪除下面指定的兩個值,禁用會話將節(jié)省一些性能消耗
- Django 中session需要依賴數(shù)據(jù)庫,因此需要確認數(shù)據(jù)庫中是否存在 與session相關(guān)的 表
- 在settings.py文件中
* 向INSTALLED_APPS列表中添加:
* 'django.contrib.sessions',
* 項MIDDLEWARE_CLASSES列表中添加:
* 'django.contrib.sessions.middleware.SessionMiddleware',
- 設(shè)置session
# 設(shè)置session
def setsess(request):
# 設(shè)置session
request.session['user'] = {'username':'李四','userid':'12314','age':20}
request.session['vip'] = {'username':'王五','userid':'12314','age':20}
return HttpResponse('設(shè)置session')
- 獲取session
# 獲取session
def getsess(request):
res = request.session.get('user',None)
if res:
return HttpResponse('歡迎'+res['username'])
else:
return HttpResponse('請登錄')
- 刪除session
# 刪除session
def outsess(request):
# 刪除會話中的一個key;注意:刪除時,如果不存在,則報錯
# del request.session['user']
# 清除所有會話信息,但不會刪除會話記錄,會話依然存在
# request.session.clear()
# 刪除當(dāng)前的會話所有的數(shù)據(jù)及記錄
# request.session.flush()
return HttpResponse('退出')
- session配置
在 settings.py 文件中進行設(shè)置:
# session 設(shè)置
SESSION_COOKIE_AGE = 60 * 30 # 30分鐘
SESSION_SAVE_EVERY_REQUEST = True #如果SESSION_SAVE_EVERY_REQUEST是True薇正,會話cookie將在每個請求中發(fā)送
SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 關(guān)閉瀏覽器,則COOKIE失效
#來自 <https://docs.djangoproject.com/en/1.11/topics/http/sessions/>
以下設(shè)置為:10秒后過期
# request.session['abc'] = 'abcdef'
# request.session.set_expiry(10)
Ajax 實例
四級城市聯(lián)動 - 思路
前提:
創(chuàng)建模型
填充數(shù)據(jù)
配置靜態(tài)文件
1. 定義路由,獲取一級城市數(shù)據(jù),返回城市聯(lián)動的html頁面
2. 在html頁面中循環(huán)并顯示一級城市數(shù)據(jù)
3. 定義一個路由,接收ajax請求
4. 在視圖函數(shù)中接收頁面?zhèn)骰氐倪x項id,回去下一級數(shù)據(jù),并返回json格式
5. 在html的頁面中動態(tài)綁定change事件,獲取id,發(fā)送ajax請求
6. 在ajax中判斷是否有返回數(shù)據(jù):如果有,返回數(shù)據(jù),并動態(tài)創(chuàng)建下拉框,添加數(shù)據(jù)
注意:
最后一級沒有數(shù)據(jù),但是創(chuàng)建選框;解決:在返回數(shù)據(jù)時進行判斷
每次選擇元素都創(chuàng)建新的選項框,不會刪除原來的選項框
解決:當(dāng)選中元素時,移除當(dāng)前元素之后的所有元素