Django流程 mvt 建立工程 路由的引導html
web 應用程序
b發送請求 -->uwsgi-->Django框架-->接收請求處理業務邏輯返回響應-->b
本質 接收請求 業務邏輯處理 返回響應前端
獲取請求request
構造response對象python
git 主分支 建立本身的分支 開發功能 測試 將開發的功能合併到分支mysql
MVC
model orm數據庫模型類
view 視圖 展現層
controller 業務邏輯層git
MVT
Models ORM數據庫模型類 進行數據庫的crud
View 接收請求 業務邏輯處理 返回響應
Template 模板渲染返回給view view經過響應返回給客戶端 template(封裝 前端文件)web
django-admin startproject 項目名
建立django項目 ajax
項目結構
├── bookmanager
│ ├── __init__.py
│ ├── settings.py 項目的總體配置文件
│ ├── urls.py 項目的url的配置文件
│ └── wsgi.py 項目與wsgi兼容web服務器的入口
└── manage.py 經過這個腳本管理工程redis
python manage.py runserver (ip:端口) 運行程序sql
能夠指定端口 也能夠不指定使用默認 shell
flask中的藍圖
對程序進行模塊化的處理 便於維護和閱讀
子應用 -->相似與flask中的藍圖
建立子應用 python manage.py startapp 子應用名字
建立子應用後的項目結構
├── book-->子應用名
│ ├── admin.py-->用於跟網站後臺管理站點配置信息相關
│ ├── apps.py-->用於配置當前子應用的相關信息
│ ├── __init__.py
│ ├── migrations-->用於存放數據庫遷移的歷史文件
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ └── __init__.cpython-35.pyc
│ ├── models.py-->用於保存數據庫模型類
│ ├── __pycache__
│ │ ├── admin.cpython-35.pyc
│ │ ├── apps.cpython-35.pyc
│ │ ├── __init__.cpython-35.pyc
│ │ └── models.cpython-35.pyc
│ ├── tests.py-->用於開發測試用例 編寫單元測試
│ └── views.py-->用於編寫web應用視圖
├── bookmanager-->項目名
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-35.pyc
│ │ ├── settings.cpython-35.pyc
│ │ ├── urls.cpython-35.pyc
│ │ └── wsgi.cpython-35.pyc
│ ├── settings.py-->項目的總體配置文件
│ ├── urls.py-->項目的url配置文件
│ └── wsgi.py-->項目與WSIG兼容的web服務器入口
├── db.sqlite3
└── manage.py-->項目管理文件 經過這個文件管理項目
註冊子應用 在 settings中INSTALLED_APPS 註冊子應用--> "子應用名.apps.子應用名首字母大寫+Config"
配置pycharm的虛擬環境 可使用which python 快速查看路徑
一對多關係 經過多的一方的外鍵進行聯繫
使用Django進行數據庫開發地步驟
定義模型類
在django中不須要定義主鍵字段 在生成列表時會自動添加而且值爲自動增加
一, 在models.py中定義模型類(django的模型類繼承自models.Model)
class 類名(models.Model)
數據庫的配置
默認是將數據放到sqlite數據庫中
在settings中 進行mysql配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #數據庫引擎改成mysql
'HOST':'127.0.0.1', # mysql的主機
'PORT':'3306', # mysql的端口
'USER':'root', # mysql的用戶
'PASSWORD':'mysql', # mysql的帳戶密碼
'NAME':'數據庫名', # ,mysql使用的數據庫 須要建立對應的數據庫
}
}
更改以後在init__py中 pymysql.install_as_MySqldb
二, 數據庫遷移
命令行中生成遷移文件 python manage.py makemigrations
執行遷移 python manage.py migrate 執行完是存在於默認的sqlite3數據表中文件中 就是settings中的默認數據庫中,配置過mysql就是在MySQL中
站點管理(內容發佈,公共訪問 兩部分)
內容發佈由網站管理員進行數據地增刪改查
django能根據定義的模型類自動地生成管理模塊
Django使用管理模塊地步驟
1本地化語言和時區 settings中 LANUAGES_CODE = "zh-hans" TIME_ZON = "Asia/Shanghai"
2建立後臺管理帳戶 python manage.py createsuperuser
3註冊模型類
在子應用地admin中註冊模型類 admin.site.register(模型類名) 在後臺中增長
4發佈內容到數據庫
在models中重寫 def__str__ (): 方法 return self.name
三, 操做數據庫
在後臺站點中添加數據
視圖和url(公共訪問)
定義視圖 在子應用地views中 其實就是python的函數
視圖函數的第一個參數必須是request實例對象
視圖函數必須返回一個HttpResponse
def index(request): # request用於接收用戶的請求
return HttpResponse("ok")
django的路由設置
首先在項目的urls.py中進行路由匹配 -----是在settings中的ROOT_URLCONFIG=""進行指定 通常不作修改
url()會和瀏覽器中輸入的進行順次匹配 有知足的就引導到相應的子應用中
urlpatterns = [url(r"^路由/"), admin.site.urls]
url的第一個參數是正則匹配 正則匹配不會對http://ip:port/和get post進行匹配
第二個參數是 引導url()匹配到本身寫的視圖中
添加規則引導url匹配到本身寫的視圖中
url(r"^", include("book.urls")),
在子應用中建立urls.py-->urlpatterns = [url(r"^用戶輸入的url$", 視圖函數名)]
在視圖函數中接收請求 處理業務邏輯 構造響應 返回響應
模板 Template
建立 模板文件夾 在settins中設置模板文件夾
在視圖函數中return render(reuuest, "模板文件",context=context)
在模板文件中接收context的鍵{{ 鍵 }}
# 安全機制
ALLOWED_HOSTS = ["*"] * 表示已全部的方式訪問 能夠指定url進行訪問
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
__file__指的是哪一個文件
os.path.abspath(__file__) 文件的絕路徑
os.path.dirname(os.path.abspath(__file__))文件的文件夾的絕對路徑
os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 文件的文件夾的文件夾的絕對路徑==項目文件夾
配置靜態文件 static
訪問靜態資源的url http//:ip"port/+STATIC_URL/+靜態資源文件名字
STATIC_URL = '/static/'
告知系統靜態資源去哪裏找
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
apps.py 是和當前子應用的配置相關
class BookConfig(AppConfig):
name = 'book'
如:verbose_name = "名字" # 能夠配置子應用在站點中的名字
MVT基本介紹
----------------------------------------------------------------------------------------------------
詳細
models -- 模型 數據的增刪改查
定義字段名 不能使用連續的下劃線__ 不能使用mysql和python的關鍵字
字段類型
null是數據庫範疇的 blank是表單驗證範疇的
CharFiled,IntegerFiled...
字段選項
db_index 提升查詢的效率 給表中的字段添加索引
unique , null ...
修改默認表名
class Meta:
db_table = "表名"
一對多 on_delete
一刪除 多刪除cascade 同步操做 級聯
一刪除 多不刪保護 拒絕protected
一刪除 多外鍵設能夠爲空 set null
插入數據 注意字段名是否一致
修改 數據庫編碼格式 alter database 庫名 cahrset utf8;
shell 工具 在shell中操做數據庫
python xxx.py shell 相似於ipython
基本查詢
從模型類中導入表
使用django查詢語句進行查詢 如 a = 表名.objects.all() 查詢到 表中的全部數據賦值給a 查詢集
增長數據
1 book = BookInfo(
字段 = '值'
)
book.save() 調用save()添加到數據庫
2 表名.objects.create(
字段='值',
) 直接加到數據庫
修改數據
1
book = 表名.objects.get(id=1) # 經過id查詢到對應的數據
book.name = '值' # 修改實力對象的屬性值
book.save() # 調用save()保存到數據庫
2
表名.objects.filter(id=1).update(
字段='值',
字段='值'
)
刪除數據
1
book = 表名.objects.get(id=1)
book.delete()
2
表名.objects.filter(id=1).delete()
表名.objects.get(id=1).delete()
刪除數據很危險 通常是修改is_delete的值(標記位)
查詢數據
基本查詢 get, all, count
表名.objects.all() -->查詢結果集 列表
表名.objects.get(id=1)-->數據對象 單一結果 數據不存在時會報數據不存在異常try它!!
表名.objects.all().count()
表名.objects.count()獲取查詢結果集的個數
get查詢出單一結果 filter過濾出多個結果(0,1,n都是多個) exclude排除掉符合條件剩下的
表名.objects.filter(查詢字段__運算符=值) 返回的查詢結果集列表
表名.objects.get(查詢字段__運算符=值) 返回的單一的數據對象
表名.objects.exclude(查詢字段__運算符=值)
日期的先後 其實就是年齡的大小 數字越大值越小 1990-1-1>1999-1-1
在1990年以後出生的人 生日是小於(lt)1990年
F 對象 兩個字段相比較
查詢閱讀量大於評論量的圖書
導入F對象
表名.objects.filter(字段__運算符=F("字段"))
Q對象 或者查詢 至關於or
表名.objects.filter(Q(字段__運算符=值)|Q(字段__運算符=值))
而且查詢 至關於and
表名.objects.filter(字段__運算符=值).filter(字段__運算符=值)
表名.objects.filter(字段__運算符=值, 字段__運算符=值)
表名.objects.filter(Q(字段__運算符=值)&Q(字段__運算符=值))
~Q 非查詢 至關於not
表名.objects.filter(~Q(字段__運算符=值)
聚合函數
Avg Max Min Count Sum
須要使用aggregate()
表名.objects.aggregate(Ju合函數("字段名")) 結果是個字典 {"字段名_聚合函數名":值}
排序
查詢結果集的排序
表名.objects.all().order_by("字段名") # 升序
表名.objects.all().order_by("-字段名")# 降序
關聯查詢 多表查詢
查詢 書籍 爲1的全部 人物 信息
經過書籍查詢人物信息
先查詢id爲1的書籍
book = BookInfo.objects.get(id=1)
經過關聯模型類名小寫_set獲取人物信息
book.peopleinfo_set.all() -->至關於在BookInfo中的隱藏字段
查詢人物爲1 的書籍信息
先查詢人物
person = PeopleInfo.objects.get(id=1)
再根據人物查詢書籍
person.book.字段 -->該字段的信息
關聯查詢的篩選
查詢圖書 圖書人物爲郭靖
經過書籍(1)去關聯人物(n)的時候的語法格式wei:
filter.(關聯模型類名小寫__字段名__運算符=值)
BookInfo.objects.filter(peopleinfo__name__exact="郭靖")
查詢書名爲"天龍八部"的全部人物
經過人物(n)關聯書籍(n)的時候的語法格式爲:
filter(外鍵值__字段名__運算符='值') # 多的一方是有外鍵的能夠直接使用
PeopleInfo.objects.filter(book__name="天龍八部")
查詢結果集
QuerSet[<對象1>,<對象2>]
all() filter() exclude() order_by() 返回的是查詢結果集 可以使用exists()判斷結果集中是否有數據
查詢結果集兩大特性
惰性 -->查詢結果集只有在使用時才生成sql語句 不使用就不進行查詢 節省數據庫性能
緩存 -->第一次查詢數據的時候,內存中沒有緩存數據,就到(數據庫)硬盤中獲取數據,第二次以後的查詢就優先從內存中讀取數據 使用變量接收查詢結果集 在屢次使用的時候 能夠從內存中進行加載 提升性能
查詢結果集支持索引 和切片操做(切片操做不持支負數)
查看MySql日誌 能夠查看對數據庫的操做記錄
使用vim 打開/etc/mysql/mysql.conf.d/mysql.cnf mysql配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
將68,69兩行的註釋代碼(默認註釋關閉日誌)打開
general_log_file =/var/log/mysql/mysql.log
general_log =1
重啓mysql服務
sudo service mysql restart
使用 sudo tail -f /var/log/mysql/mysql.log 打開mysql日誌文件 實時查看數據庫日誌內容
每次操做數據庫都會記錄操做日誌
URLconf
路由的頻繁變化時能夠:reverse反解析-------先後端不分離可使用使用
正則匹配的路由 視圖函數名 指定路由的名字即 正則匹配的路由的名字
子應用的url(r'^', booklist,name="路由的名字")
在子應用的視圖函數中使用reverse("指定的路由的名字") 經過指定的路由的名字反解析獲得對應的路由
修改的時候修改路由就能夠 reverse 相似於flask中的url_for()
防止在不一樣的應用中路由重名
經過項目url(r'^', include('book.urls',namespace='子應用名')) # 命名空間最好設置爲不能重複的子應用名
在子應用的url(r'^', booklist,name="路由的名字") # 指定路由的名字
在子應用的視圖函數中使用reverse("子應用名:路由的名字") # 使用reverse反解析獲得對應的路由
view 視圖
視圖函數必須接收一個HttpRequest對象
視圖函數必須返回一個HttpResponse對象或 子對象 做爲響應 子對象JsonResponse HttpResponseRedirect
HttpRquest 對象
請求傳遞參數的四種形式
一 提取url的特定部分 在服務端路由中使用正則截取-->/baidu/index/2019
二 查詢字符串 querystring keyword = 關鍵字--->如商品的搜索
三 請求體body中發送的數據 post請求 form ajax json xml-->如登錄註冊
四 請求頭 http報文的headers中
一 提取url的特定部分-->在服務端路由中使用正則截取
1 URL路徑參數
經過正則分組獲取的數據 會傳遞給視圖函數 視圖參數使用參數接收 (兩種方式)
.位置參數
url(r"^(\d+)/(\d+)$",視圖函數名)
def people(request,category_id,book_id ): # 位置參數的位置要一一對應
return HttpResponse("xxxx")
.關鍵字參數-->根據正則分組設置的標識符進行賦值 能夠避免位置錯誤
url(r"^(?P<category_id>\d+)/(?P<book_id>\d+)$",視圖函數名)-->(分組) 使用正則匹配分組裏的值
def people(request,book_id,category_id): # 位置參數的位置不需一一對應,可是名字必須一致
return HttpResponse("xxxx")
二 查詢字符串-->在get請求的路徑後面/?key=value&key=value 多個值之間使用&來分割
?前面的訪問的路徑 ?後面是參數-->get請求的參數
?後面的查詢字符串不參與正則匹配 只匹配請求的路徑
傳過來的參數能夠經過 request.GET 獲取到 獲取到的值是一個QueryDict:{"key":["value1","value2"],..}
QueryDict-->能夠實現一鍵多值的字典
經過鍵獲取QueryDict中多個值使用 getlist("key")
三 請求體中post請求 form ajax json xml 等 或者藉助postman工具
403 Foribidden 禁止訪問 -->須要傳CSRFToken
form-->request.POST.getlist("a")
json
請求體中的json請求 實質就是在請求頭(http報文的headers)中添加了ContentType/application/json
json-->是雙引號
1接收json數據request.body
2接收到的數據是bytes類型 須要進行轉換.decode()
3轉換以後是str類型 須要使用.loads()進行轉換 轉換爲字典類型<-->dumps()字典轉字符串
4字典數據就能夠 經過鍵獲取值
四 請求頭 在http報文的headers中
META
接收請求頭的信息 request.META 獲得的是一個子類類型的json數據 能夠直接使用get獲取值
request的其它幾個信息
method請求方法
user請求的用戶對象 若是用戶登陸 獲取用戶信息 若是沒有登錄 Django會提供一個匿名用戶AnonymousUser
FILES 請求圖片
響應HttpResponse(返回的內容,響應狀態碼)
返回的內容content(bytes類型)
返回的類型content_type MIME類型 格式爲 大類/小類 ->(application/json image/jpg)
響應狀態碼 status=狀態碼
403 forbidden 500 server error 200 ok 404 not found 300重定向 405方法不被容許
HttpResponse的子類
1 JsonResponse()-->前端發送的json格式請求 後端返回json格式響應 類字典格式
data = {
'a':'1'
}
JsonResponse(data)-->能夠將字典數據轉換爲json格式數據-->源碼的json.dumps方法和設置content_type
HttpResponse(data, content_type="application/json")
須要將data轉換格式data_json = data.dumps(data)-->默認的格式是text
須要傳入content_type="application/json" -- JsonResponse(data)已經過源碼實現 對移動端有影響
將字格式轉換爲json格式 須要將safe參數設爲False 徹底知道數據安全的狀況下(類字典數據格式)
2redirect 重定向
return redirect("/路由") # 重定向到指定的路由
狀態保持 套路
1 先從概念入手 cookie將數據保存在客戶端 session將數據保存在服務端
2 再從原理(流程)入手
第一次請求沒有cookie 服務端返回一個cookie(放在響應頭中) 以後的請求就在請求頭中攜帶cookie
在響應中設置cookie
response = HttpResponse("set_cookie")
response.set_cookie("username",username)
return response
獲取cookie
request.COOKIES 是一個字典
經過.get()獲取cookie的值
刪除cookie
response.delete_cookie("username")
session 須要依賴於cookie
發送帶有用戶名和密碼的post請求
將session數據保存在內存中
將sessionid放在cookie中返回給瀏覽器
瀏覽器發送帶有sessionid的cookie
服務端根據sessionid獲取用戶信息
返回響應信息
設置session
第一次登錄
request.GET.get("username")
request.session['username']=username
獲取session
request.session.get("username")
刪除指定session
del rquest.session["username"]
刪除全部session 保留sessionid
request.session.clear()
刪除session全部信息
request.session.flush()
設置session的有效期
requset.set_expiry(value)
3 應用場景 如 購物車(cookie)
4 本身遇到的問題,我的看法
Django 默認啓用session 默認保存在數據庫中
將session保存到redis 設置session的引擎 爲redis
安裝dajngo-redis 設置緩存CACHES
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/7',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
類視圖 面向對象的視圖函數 能夠對應不一樣的請求方法來完成對應的功能 封裝 繼承 多態
定義類視圖
# 繼承自View 須要導入
# 類視圖中定義的方法 就是http 的請求方式
# 通過url的引導 url的第二個參數引導到相應的視圖函數中 view.RegisterView.as_view()
class RegisterView(View): # 繼承自View 須要導入
def get(self,request): # GET請求方式
return HttpResponse()或其子類
def post(self,request): # POST請求方式
return HttpResponse()或其子類
類視圖使用時須要使用裝飾器
1裝飾器 裝飾在 url 的第二個參數 路由函數名處 可行
2@method_decorator()裝飾在類上 裝飾的函數時dispatch
3Mixin-->多繼承的實際應用 就是使用多繼承
使用super逐一調用全部父類 遵循mro順序 mor順序是死的
class AAA(object):
def play:
pass
class BBB(object):
def eat:
pass
class Man(BBB,object):
play-->只play
class Woamn(AAA,object):
eat-->只eat
calss Cat(AAA,BBB,object) #多繼承
play eat-->都搞
多繼承就是隻想 重寫as_view方法
1 定義裝飾器
def login_required(view_func):
def wrapper(request):
if True:
return view_func(request)
else:
return HttpResponse("請先登陸")
return wrapper
2 定義Mixin類
class LoginRequiredMinxi(object):---->B | View-->C
@classmethod
def as_view():
view = super.as_view():
view = 裝飾器(view)
return view
3 定義類視圖繼承自Mixin類 和 View類 Mixin類會爲類視圖中全部的方法添加裝飾器
class Profile(LoginRequiredMixin, View): --->A
def get(self, request):
return HttpResponse("多繼承我的中心展現")
def post(self, request):
return HttpResponse("多繼承我的中心資料修改")
多繼承--->只針對A進行分析
重寫父類super時遵循mro順序
從模型類中導入表 表.__mro__ 查看mro順序
直接在pycharm中查看繼承關係
中間件 -->相似於flask中的hook函數
# 中間件 ---> 相似flask中 hook函數
def book_middleware(get_response):
# 初始化的位置
# 相似於before_first_request
print('init')
def middleware(request):
# 請求前
# 相似於 before_request
print("before_request")
response = get_response(request)
# 響應後
# 相似於 after_request
print("after_request")
return response
return middleware
# 在settings 中註冊中間鍵
# MIDDLEWARE中 "子應用名.中間件模塊名.中間件函數名"
before_first_request 會執行兩次 將DEBUG = True設爲False就行了
befor_request 是按照註冊順序執行
after_request 是反序執行
1befor_request1
2befor_request2
2after_request2
1after_request1
站點操做
先後端不分離--Flask xjzx b--請求--s接收--查詢db--渲染模板--返回數據--返回的是html頁面(html頁面是後端經過數據返回的) 只能提供瀏覽器使用
先後端分離 對外提供統一的API(視圖,接口) 統一返回json數據
移動端要的是json數據 不能返回html了 就要先後端分離
RESTful API風格 定義接口的規範
請求相關
使url更加簡潔 將類型 id 版本 域名 等參數放到url中
1將接口儘可能 放在專有域名下
2將api的版本號放入url----GitHub是將版本號放在請求頭中的
3定義api的具體資源儘可能使用名詞的複數形式
如:
獲取單個產品:http://127.0.0.1:8080/AppName/rest/products/1
獲取全部產品: http://127.0.0.1:8080/AppName/rest/products
HTTP動詞 請求方式(對應SQL操做)
GET(SELECT)-->從服務器獲取資源一項或多項 R
POST(CREATE)-->在服務器新建數據 C
PUT(UPDATE)-->在服務器更新數據(改變後的數據由前端提供)U
DELETE(DELETE)-->從服務器刪除資源 D
示例
新增書籍 - POST/books/
不經常使用的
PATCH(UPDATE):在服務器更新(更新)資源(客戶端提供改變的屬性)。
HEAD:獲取資源的元數據。
OPTIONS:獲取信息,關於資源的哪些屬性是客戶端能夠改變的。
將經常使用參數(limit,page,sortby)放在查詢字符串中過濾返回結果
響應相關
返回更加具體的響應狀態碼
返回資源對象 或資源對象列表
超媒體 返回的類json數據 裏面是媒體文件的連接 最終是json數據
儘可能使用json 避免使用xml(標籤語言)
Django REST Framework 序列化 -->將對象(模型)數據<-->操做數據庫<-->字典(json)數據<-- 反序列化
--->23日實現
Django REST Framework 實現的事情
1 將請求的json數據轉換爲模型對象
2 將模型對象轉換爲響應的json數據
3 對模型的增刪改查
序列化器serializer 作的2件事 --> 序列化和反序列化
序列化器的做用
Serializer字段處理原始值(json)和內部數據(模型)類型之間的轉換 它們還處理驗證輸入值
1 模型-->json
2 處理驗證輸入值
3 json-->模型
模型-->json
定義一個序列化器
1繼承自這個類 serializers.Serializer
2序列化器的字段分爲三部分
字段名: 和模型的字段名一致
字段類型: 和模型中的類型一致
字段選項: read_only只讀=True
lable 註釋
max_length最大長度
class BookInfoSerializer(serializers.Serializer):
"""將模型對象轉換爲json數據(字典)"""
模型字段的名字:模型的值
name=serializers.CharField()
pub_date=serializers.DateField()
id=serializers.IntegerField()
...其它全部字段
序列化 將模型傳遞給序列化器 模型轉字典操做
在視圖中
獲取一個模型
book = BookInfo.objects.get(id=1)
建立序列化器
單個模型序列化器
serializer = BookInfoSerializer(instace=book) isntance= 實例對象(模型對象)
多模型序列化器
serializer = BookInfoSerializer(instace=book, many=True)
經過序列化器的data屬性來獲取轉換後的字典數據
serializer.data
將字典數據轉換爲字典數據
JsonResponse(serializer.data)
OrderedDict-->是有序字典[ OrderedDict([('id',1),('name','天龍八部'),...]) ]
#外鍵 只是獲取外鍵的數據 並不修改外鍵的而數據 因此要設置read_only=True
book=serializer.PrimaryKeyReliateField(label='圖書', read_only=True)
#將外鍵所關聯的數據傳遞給它 他本身會默認匹配相關的數據 獲取關聯的書籍id
book=serializer.PrimiaryKeyRelatedField(label='圖書',queryset=BookInfo.objects.all())-->對應數值
#指向模型對應的__str__()方法返回的數據 獲取關聯的書籍名
book = serializers.StringRelatedField(label='圖書')-->對應書籍名
# 獲得關聯的書籍的全部信息-->人物對應的書籍的全部信息
book = BookInfoSerializer()
序列化器的本質其實就是字段 Field
經過關聯模型類名小寫_set獲取人物信息
book.peopleinfo_set.all()-->至關於在BookInfo中的隱藏字段 一的一方的外鍵對應多我的物 獲取多我的物
反序列化 將接收的json數據轉換成模型對象
一 驗證前端提交的數據--前端的數據不可信
二 保存
一 驗證數據數據的類型和選項
1對數據的類型進行驗證 在序列化器中定義的類型 必須知足 字段的類型 其實就是一種驗證
好比: 日期date 前端就必須傳一個日期類型的數據'2000-1-1'
2對選項的驗證 如 max_length(CharField) ,min_value(Integer) read_only等
3對某一個 數據進行單獨驗證 (進一步驗證) 在序列化器中
def validate_字段名(self,value)
驗證代碼
拋出異常raise serializers.ValidationError("異常信息")
return value-->返回值必須 !
4多個字段進行驗證你
能夠實現def validate(self,attrs) 方法
def validate(self,attrs): # attrs-->就是在初始化序列化器是傳過來的data=data
# 驗證代碼
拋出異常raise serializers.ValidationError("異常信息")
rturn attrs-->必須返回值
5對單個字段定義本身的驗證方法
先定義一個方法
def aaa(self):
raise serializers.ValidationError("異常信息")
在序列化器的字段的選項中添加方法名validators['aaa']
驗證數據的基本流程
組織數據 -->接收的數據
data = {"pub_date":"2000-1-1"}-->默認的字段+選項 要求必須傳入可以使用required=True/False進行設置
建立序列化器
serializer = BookInfoSerializer(data=data(要驗證的數據))
調用序列化器的驗證方法來實現驗證
serializer.is_valid(raise_exception = True)
二 保存 數據
序列化器的反序列化
1接收前端提交的數據
2驗證數據
使用序列化器實現驗證
不驗證的數據不能入庫 必須驗證
3保存數據
當咱們使用save()方法進行保存數據的時候
須要本身實現create()方法 實現(重寫)就是爲了將數據保存到模型中
def create(self, validated_data):
傳過來的data通過驗證以後徹底符合驗證規則的時候 validated_data就應該等於data
book = BookInfo.objects.create(**validated_data)-->解包
return book
4返回響應
更新數據傳遞模型實例對象 和 驗證數據的時候 須要手動實現update()方法
serializer = BookInfoSerializer(instace=book, data=data)
def update(self, instance, validated_data):
傳過來的data通過驗證以後徹底符合驗證規則的時候 validated_data就應該等於data
instance.name = validated_data.get("name", instance.name)-->修改屬性值
instance.save()-->模型類的save()方法
return instance-->返回對象
ModelSerializer 與 Serializer
ModelSerializer繼承自(Serializer)
1自動實現create()update()方法
2根據模型自動生成字段
3必須有model
class BookInfoModelSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo
# 默認顯示全部字段
fields = '__all__'
# fields = ['id', 'readcount'..]指定顯示哪些字段
# 修改自動生成的字段的信息
extra_kwargs = {
# '字段名':{
# '選項1':'值1',
# '選項2':'值2'
# }
}
# 指定只讀屬性的字段
read_only_fields = ['字段1', '字段2']
# ModelSerializer 自動實現
from book.serializers import BookInfoModelSerializer
serializer = BookInfoModelSerializer()
serializer
Serializer繼承自(BaseSerializer)
本身定義使用
視圖
rest framework 的三種視圖
1 APIVAiew 繼承自View 是DRF的基類 一級視圖
和View使用方法同樣
請求和響應是本身實現的
接收請求的數據 不用判斷 post,put是request.data get是request.query_paramas
響應 統一使用Response()返回數據 裏面依然是字典/json數據 狀態碼
from rest_framework import APIView
class BookAPIView(APIView):
def get(self, request): # 獲取書籍信息
books = BookInfo.objects.all()
serializer = BookInfoModelSerializer(instance=books, many=True)
return Response(serializer.data)
2 GenericAPIView 通用視圖 二級視圖
from rest_framework.generics import GenericAPIView
用法和APIView基本同樣
爲標準列視圖 和詳細信息視圖添加了經常使用的行爲
提供每一個具體通用視圖是經過 GenericAPIView 與一個或者多個 Mixin類 組合而成的
GenericAPIView的兩個方向
1GenericAPIView 對列表視圖和詳情視圖 作了一些 屬性 和 方法 的抽取
2和Mixin類配合使用
屬性
queryset = BookInfo.objects.all() 設置查詢結果集
serializer_class = BookInfoModelSerializer 設置序列化器
lookup_field = 'xx' 設置url中的關鍵字參數
方法
get_queryset 獲取 queryset中的查詢結果集
get_serializer 獲取 serializer_class 所對應的序列化器 同時完成序列化器的初始化工做
get_object 獲取 lookup_field = 'xx' 中的xx指定的數據 根據xx查詢出來的數據
列表視圖
class BookGenericAPIView(GenericAPIView):
def get(self, request):
# books = self.queryset
books = self.get_queryset()
# serializer = self.serializer_class(books, many=True)
serializer = self.get_serializer(books, many=True)
return Response(serializer.data)
詳情視圖
class BookDetailGenericAPIView(GenericAPIView):
queryset = BookInfo.objects.all() 不是到具體用的哪一個 就查詢全部
serializer_class = BookInfoModelSerializer 設置序列化器
lookup_field = 'xx' 設置url中的關鍵字參數
def get(self, request, pk):->默認四經過pk來獲取url中的id的信息的 能夠本身修改lookup_field='id'
book = self.get_object(pk)
serializer = self.get_serializer(instance = book)
return Response(serializer.data)
GenericAPIView和Mixin類配合使用(ListModelMixin, CreateModelMixin, GenericAPIView)
get list()方法 -- 獲取數據
post create()方法--新增數據
get retrieve()--的獲得一條數據
put update() --修改一條數據
delete destory()-- 刪除一條數據
三級視圖
ListAPIview ,CreatAPIView...
queryset=BookInfo.objects.all()
serializer=BookInfoModelSerializer
視圖集 ViewSet將一組相關的視圖的邏輯放到一個類中 成爲視圖集
在視圖集中不能由相同的方法名 如get獲取所有信息 get獲取某一信息
因此視圖集提供了
list() create() retieve() update() partial_update()局部更新 destory()等方法 避免了方法重名
ViewSet不提供任何方法處理程序 須要咱們本身重寫該類並,明確實現action方法
url的引導
無參數時是查詢全部 url(r'^books/$',視圖集名.as_view({"get":"list"})
有參數時是查詢一個 url(r'^books/(?P<pk>\d+)/$',視圖集名.as_view({"get":"retrieve"})
自動生成url
從rest.framework.routers中導入DefaultRouter
初始化路由器router=DefaultRouter()
註冊路由器router.register(r'books',views.視圖集名,base_name='xxx') 就不須要再urlpatterns中添加了
只須要 urlpatterns += router.urls 就能夠
優點 自動生成url 重複的邏輯能夠合併成一個類,定義一次屬性 queryset 和 serializer_class
GenericViewSet
繼承自GenericAPIView,做用也與GenericAPIVIew相似,提供了get_object、get_queryset等方法便於列表視圖與詳情信息視圖的開發。在GenericAPIView中,沒有提供任何動做action方法,須要咱們本身覆蓋該類並混合所需的混合類,或者明肯定義操做實現action方法
ModelViewSet 繼承自 五個Mixin和GenericViewSet
等因而二級視圖GenericAPIView和Mixin類的配合使用 一次配合了五個Mixin類
須要提供queryset 和 serializer
使用@action(methods=['post'], detail=True)裝飾器配合使用
ReadOnlyModelViewSet
繼承自GenericAPIVIew,同時包括了ListModelMixin、RetrieveModelMixin。
與ModelViewSet它同樣,它還包括各類操做的實現,但不一樣於ModelViewSet只提供「只讀」操做,
list()並且retrieve()
其它功能
概念 配置 效果
認證 通常和權限配合使用
配置
DRF的配置key
REST_FRAMEWORK = {# 全局認證
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication', # 基本認證 僅適用於測試
'rest_framework.authentication.SessionAuthentication', # session認證
)
}
認證失敗
401未認證
403權限被禁止
權限
Django提供的四種權限 AllowAny IsAuthenticated IsAdminUser IsAuthenticatedOrReadOnly
配置
DRF的配置key
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', # 登錄用戶 經過認證的用戶 才能夠訪問
)
}
某一個視圖讓全部人均可以訪問
再單個視圖中設置權限
從 rest_framework.permissions導入 權限
在視圖中相加相應的權限permission_calssses=[AllowAny]-->這個權限大於settings中的
還能夠單獨設置身份認證authentication_calsses=[]
限流--限制訪問的頻次 減輕服務器的壓力(是一個安全機制)
配置REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',# 限制匿名用戶
'rest_framework.throttling.UserRateThrottle'# 限制登錄用戶
),
'DEFAULT_THROTTLE_RATES': {# 設置頻次
'anon': '100/day',# 匿名用戶頻次
'user': '1000/day'# 登錄用戶頻次 單位 day hour minute seconds
}
}
過濾 根據條件進行數據的篩選filter_name = []
安裝pip install django_filters
INSTALLED_APPS = [
...
'django_filters',
...
]
配置
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
在視圖中設置過濾的字段filter_fields=['字段','字段',...]/?id=10
排序
從 rest_framework導入OrderingFilter
filter_backends = [OrderingFilter]
設置排序的字段
ordering_fields = ['字段','字段',...]/?ordering=readcount
分頁
從rest_framework.pagination中導入LimitOffsetPagination
pagination_class = LimitOffsetPagination
PageNumberPagination
版本
異常處理
統一處理數據
處理數據庫的異常
定義和系統同樣的函數exception_handler
判斷響應是不是None是的話就判斷是否是數據庫異常 本身定義方法解決
DRF的異常類
APIException 全部異常的父類
ParseError 解析錯誤
AuthenticationFailed 認證失敗
NotAuthenticated 還沒有認證
PermissionDenied 權限決絕
NotFound 未找到
MethodNotAllowed 請求方式不支持
NotAcceptable 要獲取的數據格式不支持
Throttled 超過限流次數
ValidationError 校驗失敗
自動生成接口文檔
pip install coreapi
設置路由 放在根url中
訪問哪一個路由就能夠
------------------------------------------------------------------------------------------------
B2B business to business 企業對企業 電子商務的主流形式
C2C custom to custom 我的對我的
B2C 企業對我的
C2B 我的對企業 消費者我的的需求進行定製
O2O線上對線下
F2C 工廠到我的
B2B2C 企業對企業對我的
積攢 bug
傳遞的不是字典數據safe=False獲取數據時能夠設置個默認值 404 的本質是路由錯誤序列化器繼承自這個類 serializers.Serializer