基礎(chǔ)介紹
1. 簡(jiǎn)介
Django担映,發(fā)音為[d???ɡ??]
,是用python語(yǔ)言寫(xiě)的開(kāi)源web開(kāi)發(fā)框架茧彤,并遵循MVC設(shè)計(jì)洋机。Django的主要目:簡(jiǎn)便、快速的開(kāi)發(fā)「數(shù)據(jù)庫(kù)」驅(qū)動(dòng)的網(wǎng)站贬媒。
學(xué)習(xí)網(wǎng)站:
官方網(wǎng)站: https://www.djangoproject.com/
github源碼:https://github.com/django/django
django中文文檔:https://yiyibooks.cn/xx/Django_1.11.6/index.html
2. 特點(diǎn)
-
重量級(jí)框架
對(duì)比Flask框架聋亡,Django原生提供了眾多的功能組件,讓開(kāi)發(fā)更簡(jiǎn)便快速际乘。
提供項(xiàng)目工程管理 自動(dòng)化腳本工具
數(shù)據(jù)庫(kù)ORM支持(對(duì)象關(guān)系映射坡倔,英語(yǔ):Object Relational Mapping)
模板
表單
Admin管理站點(diǎn)
文件管理
認(rèn)證權(quán)限
session機(jī)制
緩存
-
MVT模式
- M全拼為Model,與MVC中的M功能相同脖含,負(fù)責(zé)和數(shù)據(jù)庫(kù)交互罪塔,進(jìn)行數(shù)據(jù)處理。
- V全拼為View养葵,與MVC中的C功能相同征堪,接收請(qǐng)求,進(jìn)行業(yè)務(wù)處理关拒,返回應(yīng)答佃蚜。
- T全拼為T(mén)emplate,與MVC中的V功能相同着绊,負(fù)責(zé)封裝構(gòu)造要返回的html谐算。
![image](https://upload-images.jianshu.io/upload_images/12041448-2817315ecaf2b5e8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3. 環(huán)境搭建
-
環(huán)境準(zhǔn)備
- python3.x
- django 3.0.4
- pycharm 專業(yè)版(專業(yè)版可以多一些django框架中界面操作的功能,社區(qū)版的話归露,需要用命令行去執(zhí)行)
- 參考別人的專業(yè)版破(和諧)解教程:https://www.cnblogs.com/sillycuckoo/p/12638868.html
安裝django
pip install django==3.0.4
4. 創(chuàng)建項(xiàng)目
-
選擇django框架+虛擬環(huán)境
指定項(xiàng)目運(yùn)行的python解釋器
Perference->Project Interpreter->選擇為虛擬環(huán)境中的python.exe-
項(xiàng)目中的文件
- 最外層的:django_project: 項(xiàng)目的容器洲脂,可以隨便命名。
- manage.py: 一個(gè)讓你用各種方式管理 Django 項(xiàng)目的命令行工具剧包。
- django_project/init.py:一個(gè)空文件恐锦,告訴 Python 這個(gè)目錄應(yīng)該被認(rèn)為是一個(gè) Python 包雇毫。
- django_project/settings.py:Django 項(xiàng)目的配置文件。
- django_project/urls.py:Django 項(xiàng)目的 URL 聲明踩蔚,就像你網(wǎng)站的“目錄”。
- django_project/wsgi.py:作為你的項(xiàng)目的運(yùn)行在 WSGI 兼容的Web服務(wù)器上的入口枚粘。
-
啟動(dòng)命令配置
![image](https://upload-images.jianshu.io/upload_images/12041448-e15f6482897c18db?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
訪問(wèn)127.0.0.1:8000馅闽,表示環(huán)境搭建成功
5. settings.py配置文件
-
app路徑配置
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app1.apps.App1Config', # 默認(rèn)已有 如果沒(méi)有只要添加app名稱即可 例如: 'app1' # 新建的應(yīng)用都要在這里添加 ]
-
數(shù)據(jù)庫(kù)配置
# 如果使用django的默認(rèn)sqlite3數(shù)據(jù)庫(kù)則不需要改 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # 如果使用mysql數(shù)據(jù)庫(kù)需要將上述數(shù)據(jù)庫(kù)注掉修改如下: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'blog', #你的數(shù)據(jù)庫(kù)名稱 數(shù)據(jù)庫(kù)需要自己提前建好 'USER': 'root', #你的數(shù)據(jù)庫(kù)用戶名 'PASSWORD': '', #你的數(shù)據(jù)庫(kù)密碼 'HOST': '', #你的數(shù)據(jù)庫(kù)主機(jī),留空默認(rèn)為localhost 'PORT': '3306', #你的數(shù)據(jù)庫(kù)端口 } }
-
靜態(tài)文件目錄
STATIC_URL = ‘/static/’ #調(diào)用時(shí)目錄 STATICFILES_DIRS=[ os.path.join(BASE_DIR,“static”), #具體路徑 ]
-
中間件
# 自己寫(xiě)的中間件馍迄,例如在項(xiàng)目中的md文件夾下md.py文件中的M1與M2兩個(gè)中間件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'md.md.M1', 'md.md.M2', ] # 注意自己寫(xiě)的中間件福也,配置要寫(xiě)在系統(tǒng)中的后面
-
session存儲(chǔ)的相關(guān)配置
# 數(shù)據(jù)庫(kù)配置(默認(rèn)) # Django默認(rèn)支持Session,并且默認(rèn)是將Session數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中攀圈,即:django_session 表中暴凑。 # 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認(rèn)) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時(shí)的key,即:sessionid=隨機(jī)字符串(默認(rèn)) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認(rèn)) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認(rèn)) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認(rèn)) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認(rèn)) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認(rèn)) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關(guān)閉瀏覽器使得Session過(guò)期(默認(rèn)) SESSION_SAVE_EVERY_REQUEST = False # 是否每次請(qǐng)求都保存Session赘来,默認(rèn)修改之后才保存(默認(rèn)) SESSION_CACHE_ALIAS = 'default' # 使用緩存的別名现喳,此處設(shè)置成redis數(shù)據(jù)庫(kù)配置的別名default
-
緩存配置
-
內(nèi)存緩存配置
# 配置緩存 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', 'KEY_PREFIX': 'lcfcn', 'TIMEOUT': None } }
-
文件緩存配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', # 文件路徑 } }
-
數(shù)據(jù)庫(kù)緩存配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 數(shù)據(jù)庫(kù)表名,任意名字即可 } }
配置完之后記得在cmd中執(zhí)行下列語(yǔ)句創(chuàng)建緩存表
python manage.py createcachetable
-
redis緩存配置
CACHES = { # 配置緩存數(shù)據(jù)為redis "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "PASSWORD":"12345" } } }
-
CACHES設(shè)置中有幾個(gè)額外的參數(shù):
TIMEOUT:緩存超時(shí)時(shí)間犬辰,默認(rèn)為300s嗦篱,可以設(shè)置為None,即永不超時(shí)幌缝。
OPTIONS : locmem, filesystem和database緩存系統(tǒng)這些有自己的剔除策略的系統(tǒng)有以下的參數(shù):
MAX_ENTRIES : 緩存中存放的最大條目數(shù)灸促,大于這個(gè)數(shù)時(shí),舊的條目將會(huì)被刪除涵卵,默認(rèn)為300.
CULL_FREQUENCY:當(dāng)達(dá)到MAX_ENTRIES的時(shí)候,被接受的訪問(wèn)的比率浴栽。實(shí)際的比率是1/cull_frequency,所以設(shè)置為2就是在達(dá)到max_entries時(shí)去除一半數(shù)量的緩存,設(shè)置為0意味著達(dá)到max_entries時(shí),緩存將被清空轿偎。這個(gè)值默認(rèn)是3典鸡。
KEY_PREFIX:一個(gè)會(huì)自動(dòng)列入緩存key值的的字符串。
VERSION:緩存key值生成時(shí)使用的版本數(shù)字贴硫。
KEY_FUNCTION:key值最終生成所使用的方法椿每。
-
6. Django常用命令
-
創(chuàng)建項(xiàng)目
django-admin startproject project_name
-
新建app
cd 項(xiàng)目根目錄
python manage.py startapp app_name
-
創(chuàng)建數(shù)據(jù)庫(kù)表 或 更改數(shù)據(jù)庫(kù)表或字段
生成遷移腳本
python manage.py makemigrations
執(zhí)行遷移腳本
python manage.py migrate
-
使用開(kāi)發(fā)服務(wù)器
開(kāi)發(fā)服務(wù)器,即開(kāi)發(fā)時(shí)使用英遭,一般修改代碼后會(huì)自動(dòng)重啟间护,方便調(diào)試和開(kāi)發(fā),但是由于性能問(wèn)題挖诸,建議只用來(lái)測(cè)試汁尺,不要用在生產(chǎn)環(huán)境。
python manage.py runserver
當(dāng)提示端口被占用的時(shí)候多律,可以用其它端口:
python manage.py runserver 8001
監(jiān)聽(tīng)機(jī)器所有可用 ip (電腦可能有多個(gè)內(nèi)網(wǎng)ip或多個(gè)外網(wǎng)ip)
python manage.py runserver 0.0.0.0:8000
如果是外網(wǎng)或者局域網(wǎng)電腦上可以用其它電腦查看開(kāi)發(fā)服務(wù)器
訪問(wèn)對(duì)應(yīng)的ip加端口痴突,比如 http://172.16.20.2:8000
-
清空數(shù)據(jù)庫(kù)
python manage.py flush
此命令會(huì)詢問(wèn)是 yes 還是 no, 選擇 yes 會(huì)把數(shù)據(jù)全部清空掉搂蜓,只留下空表。
-
創(chuàng)建超級(jí)管理員
python manage.py createsuperuser
按照提示輸入用戶名和對(duì)應(yīng)的密碼就好了郵箱可以留空辽装,用戶名和密碼必填
修改用戶密碼可以用:
python manage.py changepassword username
-
導(dǎo)出數(shù)據(jù) 導(dǎo)入數(shù)據(jù)
python manage.py dumpdata appname > appname.json
python manage.py loaddata appname.json
-
Django 項(xiàng)目環(huán)境終端
python manage.py shell
如果你安裝了 bpython 或 ipython 會(huì)自動(dòng)用它們的界面帮碰,推薦安裝 bpython。
這個(gè)命令和 直接運(yùn)行 python 或 bpython 進(jìn)入 shell 的區(qū)別是:你可以在這個(gè) shell 里面調(diào)用當(dāng)前項(xiàng)目的 models.py 中的 API拾积,對(duì)于操作數(shù)據(jù)殉挽,還有一些小測(cè)試非常方便。
-
數(shù)據(jù)庫(kù)命令行
python manage.py dbshell
Django 會(huì)自動(dòng)進(jìn)入在settings.py中設(shè)置的數(shù)據(jù)庫(kù)拓巧,如果是 MySQL 或 postgreSQL,會(huì)要求輸入數(shù)據(jù)庫(kù)用戶密碼斯碌。
在這個(gè)終端可以執(zhí)行數(shù)據(jù)庫(kù)的SQL語(yǔ)句。如果您對(duì)SQL比較熟悉肛度,可能喜歡這種方式傻唾。
-
反向生成model
python manage.py inspectdb
-
更多命令
python manage.py
可以看到詳細(xì)的列表,在忘記子名稱的時(shí)候特別有用承耿。
視圖
1. 視圖函數(shù)
-
介紹
一個(gè)視圖函數(shù)冠骄,簡(jiǎn)稱視圖,是一個(gè)簡(jiǎn)單的Python函數(shù)加袋,它接受Web請(qǐng)求并且返回Web響應(yīng)猴抹。響應(yīng)可以是一張網(wǎng)頁(yè)的HTML內(nèi)容,一個(gè)重定向锁荔,一個(gè)404錯(cuò)誤蟀给,一個(gè)XML文檔,或者一張圖片阳堕,是任何東西都可以跋理。無(wú)論視圖本身包含什么邏輯,都要返回響應(yīng)恬总。代碼寫(xiě)在哪里也無(wú)所謂前普,只要它在你的Python目錄下面。除此之外沒(méi)有更多的要求了——可以說(shuō)“沒(méi)有什么神奇的地方”壹堰。為了將代碼放在某處拭卿,約定是將視圖放置在項(xiàng)目或應(yīng)用程序目錄中的名為views.py的文件中。
視圖函數(shù):
一定包含兩個(gè)對(duì)象:
request---->用戶請(qǐng)求相關(guān)的所有信息(對(duì)象)
Httpresponse---->響應(yīng)字符串
-
簡(jiǎn)單的視圖demo
from django.http import HttpResponse # 導(dǎo)入了HttpResponse類 # 我們定義了hello_world函數(shù)贱纠。它就是視圖函數(shù)峻厚。 # 每個(gè)視圖函數(shù)都使用HttpRequest對(duì)象作為第一個(gè)參數(shù),并且通常稱之為 request谆焊。 def helloworld(request): return HttpResponse("helloworld!hello,測(cè)開(kāi)大佬!")
-
配置路由
主路由惠桃,即項(xiàng)目下的urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('test/',include('views_demo.urls')) ]
子路由,即app下的urls.py
from django.urls import path from views_demo import views urlpatterns = [ path('helloworld/',views.helloworld), ]
-
根據(jù)路由訪問(wèn)示例
展示了views.py中定義的helloworld函數(shù)的返回
2. 請(qǐng)求和響應(yīng)
視圖函數(shù),圍繞著兩個(gè)對(duì)象進(jìn)行:HttpResponse和HttpRequest
-
HttpRequest
request---->請(qǐng)求信息
request.path # 獲取訪問(wèn)文件路徑 request.method屬性 #獲取請(qǐng)求中使用的HTTP方式(POST/GET) request.body #含所有請(qǐng)求體信息 是bytes類型 request.GET #GET請(qǐng)求的數(shù)據(jù)(類字典對(duì)象) 請(qǐng)求頭中的url中?后面拿值 request.POST # POST請(qǐng)求的數(shù)據(jù)(類字典對(duì)象) 請(qǐng)求體里拿值 request.COOKIES #包含所有cookies的標(biāo)準(zhǔn)Python字典對(duì)象辜王;keys和values都是字符串劈狐。 request.FILES:包含所有上傳文件的類字典對(duì)象;FILES中的每一個(gè)Key都是<input type="file" name=""/>標(biāo)簽中name屬性的值呐馆,F(xiàn)ILES中的每一個(gè)value同時(shí)也是一個(gè)標(biāo)準(zhǔn)的python字典對(duì)象肥缔,包含下面三個(gè)Keys: - filename:上傳文件名,用字符串表示 - content_type:上傳文件的Content Type - content:上傳文件的原始內(nèi)容 request.user:是一個(gè)django.contrib.auth.models.User對(duì)象汹来,代表當(dāng)前登陸的用戶辫继。如果訪問(wèn)用戶當(dāng)前沒(méi)有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的實(shí)例俗慈。你可以通過(guò)user的is_authenticated()方法來(lái)辨別用戶是否登陸:if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware時(shí)該屬性才可用 request.session:唯一可讀寫(xiě)的屬性,代表當(dāng)前會(huì)話的字典對(duì)象遣耍;自己有激活Django中的session支持時(shí)該屬性才可用 request.GET.get('name') 拿到GET請(qǐng)求里name的值 如果某個(gè)鍵對(duì)應(yīng)有多個(gè)值闺阱,則不能直接用get取值,需要用getlist舵变,如:request.POST.getlist("hobby") 請(qǐng)求url:http://127.0.0.1:8000/index.html/23?a=1 request.path : 請(qǐng)求路徑 request.path結(jié)果為:/index.html/23 request.get_full_path() request.get_full_path()結(jié)果為:/index.html/23?a=1
可以自己在視圖函數(shù)中打印下試試酣溃,可在控制臺(tái)看到:
def helloworld(request): print(request.path) print(request.GET) print(request.body) return HttpResponse("helloworld!hello,測(cè)開(kāi)大佬!")
-
HttpResponse
HttpResponse---->響應(yīng)字符串
對(duì)于HttpRequest請(qǐng)求對(duì)象來(lái)說(shuō),是由django自動(dòng)創(chuàng)建的纪隙,但是赊豌,HttpResponse響應(yīng)對(duì)象就必須我們自己創(chuàng)建。每個(gè)view請(qǐng)求處理方法必須返回一個(gè)HttpResponse響應(yīng)對(duì)象绵咱。HttpResponse類在django.http.HttpResponse碘饼。
常用屬性:
content:返回的內(nèi)容。 response = HttpResponse() response.content = '果芽軟件' return response status_code:返回的HTTP響應(yīng)狀態(tài)碼 content_type:返回?cái)?shù)據(jù)的mime類型
常用方法:
set_cookie:用來(lái)設(shè)置cookie信息 delete_cookie:用來(lái)刪除cookie信息悲伶。 write:HttpResponse是一個(gè)類似于文件的對(duì)象艾恼,可以用來(lái)寫(xiě)入數(shù)據(jù)到數(shù)據(jù)體(content)中。
-
JsonResponse對(duì)象
# 把字典或者列表當(dāng)做抓換成json數(shù)據(jù)并返回 def test_redirect(request): return JsonResponse([{"code":0000,"msg":'成功'}],safe=False) # 數(shù)據(jù)類型為列表麸锉,必須指定safe=False # return JsonResponse({"code":0000,"msg":'成功'},safe=False) # 數(shù)據(jù)類型為字典钠绍,不必指定safe
-
其他常用響應(yīng)函數(shù)和對(duì)象
-
render 函數(shù)(前后端分離開(kāi)發(fā),不需要掌握花沉,了解即可)
將指定頁(yè)面渲染后返回給瀏覽器
render(request, template_name[, context])
結(jié)合一個(gè)給定的模板和一個(gè)給定的上下文字典柳爽,并返回一個(gè)渲染后的 HttpResponse 對(duì)象。
-
redirect 函數(shù)
參數(shù)可以是:
一個(gè)模型:將調(diào)用模型的get_absolute_url() 函數(shù)
一個(gè)視圖碱屁,可以帶有參數(shù):將使用urlresolvers.reverse 來(lái)反向解析名稱
一個(gè)絕對(duì)的或相對(duì)的URL磷脯,將原封不動(dòng)的作為重定向的位置。默認(rèn)返回一個(gè)臨時(shí)的重定向娩脾;傳遞permanent=True 可以返回一個(gè)永久的重定向争拐。
-
3. 類視圖
>以函數(shù)的形式進(jìn)行定義的視圖就是函數(shù)視圖,視圖函數(shù)便于理解,但是遇到一個(gè)視圖函數(shù)對(duì)應(yīng)的路徑提供了多種不同的HTTP請(qǐng)求方式的支持時(shí)(get,post,delete,put),需要在一個(gè)函數(shù)中寫(xiě)不同的業(yè)務(wù)邏輯,代碼的可讀性和復(fù)用性就很低, 所以,我們引入類視圖進(jìn)行解決。
-
未使用類視圖
def register(request): """處理注冊(cè)""" # 獲取請(qǐng)求方法,判斷是GET/POST請(qǐng)求 if request.method == 'GET': # 處理GET請(qǐng)求架曹,返回注冊(cè)頁(yè)面 return render(request, 'register.html') else: # 處理POST請(qǐng)求隘冲,實(shí)現(xiàn)注冊(cè)邏輯 return HttpResponse('這里實(shí)現(xiàn)注冊(cè)邏輯')
-
使用類視圖示例
class DefineClassview(View): """演示類視圖的定義和使用""" def get(self, request): """處理GET請(qǐng)求業(yè)務(wù)邏輯""" return HttpResponse('GET請(qǐng)求業(yè)務(wù)邏輯') def post(self, request): """處理POST請(qǐng)求業(yè)務(wù)邏輯""" return HttpResponse('POST請(qǐng)求業(yè)務(wù)邏輯') def put(self, request): pass
-
類視圖的使用
定義類視圖需要繼承自的Django提供的父類的View
-
導(dǎo)入
from django.views.generic import View
-
示例 :views.py
from django.http import HttpResponse from django.views import View #導(dǎo)入View class ViewDemo(View): def get(self,request): return HttpResponse("get方法被調(diào)用") def post(self,request): return HttpResponse("post方法被調(diào)用") def put(self,request): return HttpResponse("put方法被調(diào)用") def delete(self,request): return HttpResponse("delete方法被調(diào)用")
-
配置路由時(shí),需要使用類視圖的as_view()方法來(lái)注冊(cè)添加
urlpatterns = [ path('',view.ViewDemo.as_view()),# 使用as_view()方法把類視圖注冊(cè)為視圖 ]
-
去掉禁用跨域訪問(wèn)的中間件
若接口返回
403 Forbidden
,注釋掉settings.py中的禁用跨域訪問(wèn)的中間件
路由
1. 單一路由
就是一個(gè)路徑對(duì)應(yīng)一個(gè)視圖函數(shù)或者視圖類
```
urlpatterns = [
path('hello/',view.hello_world),
path('',view.ViewDemo.as_view()),# 使用as_view()方法把類視圖注冊(cè)為視圖
]
```
2. 基于正則的路由
前邊的寫(xiě)法绑雄,我們?cè)谠L問(wèn)一個(gè)接口的時(shí)候展辞,接口地址最后邊必須要帶一個(gè)/但是這樣看著極度不美觀。我們就可以通過(guò)基于正則表達(dá)式的路由幫我們解決万牺。
注意:
- 基于正則表達(dá)式的路由必須使用re_path而不是我們之前用的path了
-
正則表達(dá)式字符串的開(kāi)頭字母“r”罗珍。它告訴Python這是個(gè)原始字符串,不需要處理里面的反斜杠(轉(zhuǎn)義字符)(2.0版本之后可以不用帶了)
urlpatterns = [ re_path(r'^hello.?$',view.ViewDemo.as_view()),# .?代表0到1個(gè)任意字符脚粟,這樣寫(xiě)我們?cè)谠L問(wèn)地址的時(shí)候就可以省略最后邊的/了 ]
3. 路由參數(shù)傳遞
-
在Django中路由參數(shù)傳遞改變了一點(diǎn)寫(xiě)法
urlpatterns = [ path("args/<pk>/",view.args_demo),# 默認(rèn)是匹配字符串 ]
-
視圖函數(shù)參數(shù)列表中需要變量來(lái)接收url參數(shù)覆旱,且視圖中的參數(shù)和上邊的關(guān)鍵字一致
def args_demo(request,pk):# 視圖函數(shù)的參數(shù)列表中需要一個(gè)變量來(lái)接收url參數(shù) print(pk) return HttpResponse("pk的值為:{}".format(pk))
-
注意:
- 要捕獲一段url中的值,需要使用尖括號(hào)
- 可以轉(zhuǎn)換捕獲到的值為指定類型核无,比如例子中的int扣唱。默認(rèn)情況下,捕獲到的結(jié)果保存為字符串類型团南,不包含/這個(gè)特殊字符噪沙;
-
還可以寫(xiě)成正則表達(dá)式的形式
urlpatterns = [ re_path(r"^args/(?P<pk>[a-zA-Z]+).?$",view.args_demo) # 正則表達(dá)式的寫(xiě)法, ] # (?P<關(guān)鍵字>) 指定正則表達(dá)式提取值的存放關(guān)鍵字 # [a-zA-Z]+ 表示匹配1到多個(gè)字母 匹配內(nèi)容根據(jù)你正則表達(dá)式來(lái)定 # (?P<pk>[a-zA-Z]+) 完整的解釋就是匹配1到多個(gè)字母,存入pk這個(gè)關(guān)鍵字中
-
url參數(shù)轉(zhuǎn)換器
urlpatterns = [ path("args/<int:pk>/",view.args_demo),# 表示匹配 int類型的參數(shù) ]
-
傳遞多個(gè)參數(shù)
path("args/<int:page>/<int:size>/",view.args_demo)
-
視圖函數(shù)中也要對(duì)應(yīng)聲明多個(gè)參數(shù)來(lái)接收
def args_demo(request,page,size):# 視圖函數(shù)的參數(shù)列表中需要一個(gè)變量來(lái)接收url參數(shù) return HttpResponse("page的值為:{},size的值為:{}".format(page,size))
-
參數(shù)傳遞默認(rèn)值
path("args/<int:page>/<int:size>/",view.args_demo,{"page":1,"size":5})
4. 路由分發(fā)
路由分發(fā)指的是一個(gè)請(qǐng)求過(guò)來(lái)之后吐根,怎么通過(guò)一級(jí)一級(jí)的轉(zhuǎn)發(fā)正歼,給到對(duì)應(yīng)的程序處理;在django中一般指的是拷橘,從主app分發(fā)到子app中
-
創(chuàng)建子應(yīng)用
python manage.py startapp app01
settings.py中引入剛創(chuàng)建的app
- 子應(yīng)用中創(chuàng)建子路由文件
- 子應(yīng)用中寫(xiě)一個(gè)視圖和路由信息局义,方便講路由分發(fā)
views.py
from django.http import HttpResponse
from django.shortcuts import render
# Create your views here.
def hello_world(request):
return HttpResponse('hello world')
urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path(r"^hello.?$",views.hello_world),
]
- 使用include分發(fā)路由
from django.urls import path, re_path, include
from django_project import view
urlpatterns = [
path("v01/",include("app01.urls")) # 主路由中使用include轉(zhuǎn)發(fā)至子路由中
]
- 重啟服務(wù)之后,瀏覽器訪問(wèn)
5. url反向解析和命名空間(這個(gè)部分沒(méi)懂冗疮,待補(bǔ)充旭咽,0524路由&視圖)
在實(shí)際開(kāi)發(fā)中,系統(tǒng)內(nèi)部某些視圖會(huì)通過(guò)redirect(url)重定向至其他的視圖來(lái)處理赌厅,但是如果url地址被改掉了穷绵,我們通過(guò)url重定向就會(huì)失敗,為了解決這個(gè)問(wèn)題特愿,引入了命名路由和命名空間的概念
ORM
- ORM 概念
對(duì)象關(guān)系映射(Object Relational Mapping仲墨,簡(jiǎn)稱ORM)模式是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在的互不匹配的現(xiàn)象的技術(shù)。 簡(jiǎn)單的說(shuō)揍障,ORM是通過(guò)使用描述對(duì)象和數(shù)據(jù)庫(kù)之間映射的元數(shù)據(jù)目养,將程序中的對(duì)象自動(dòng)持久化到關(guān)系數(shù)據(jù)庫(kù)中。 ORM在業(yè)務(wù)邏輯層和數(shù)據(jù)庫(kù)層之間充當(dāng)了橋梁的作用
- ORM 由來(lái)
讓我們從O/R開(kāi)始毒嫡。字母O起源于"對(duì)象"(Object)癌蚁,而R則來(lái)自于"關(guān)系"(Relational)。 幾乎所有的軟件開(kāi)發(fā)過(guò)程中都會(huì)涉及到對(duì)象和關(guān)系數(shù)據(jù)庫(kù)。在用戶層面和業(yè)務(wù)邏輯層面努释,我們是面向?qū)ο蟮摹?當(dāng)對(duì)象的信息發(fā)生變化的時(shí)候碘梢,我們就需要把對(duì)象的信息保存在關(guān)系數(shù)據(jù)庫(kù)中。 按照之前的方式來(lái)進(jìn)行開(kāi)發(fā)就會(huì)出現(xiàn)程序員會(huì)在自己的業(yè)務(wù)邏輯代碼中夾雜很多SQL語(yǔ)句用來(lái)增加伐蒂、讀取煞躬、修改、刪除相關(guān)數(shù)據(jù)逸邦, 而這些代碼通常都是極其相似或者重復(fù)的
- ORM 優(yōu)勢(shì)
ORM解決的主要問(wèn)題是對(duì)象和關(guān)系的映射恩沛。它通常將一個(gè)類和一張表一一對(duì)應(yīng),類的每個(gè)實(shí)例對(duì)應(yīng)表中的一條記錄缕减, 類的每個(gè)屬性對(duì)應(yīng)表中的每個(gè)字段雷客。 ORM提供了對(duì)數(shù)據(jù)庫(kù)的映射,不用直接編寫(xiě)SQL代碼桥狡,只需操作對(duì)象就能對(duì)數(shù)據(jù)庫(kù)操作數(shù)據(jù)搅裙。 讓軟件開(kāi)發(fā)人員專注于業(yè)務(wù)邏輯的處理,提高了開(kāi)發(fā)效率总放。
- ORM 劣勢(shì)
ORM的缺點(diǎn)是會(huì)在一定程度上犧牲程序的執(zhí)行效率。 ORM的操作是有限的好爬,也就是ORM定義好的操作是可以完成的局雄,一些復(fù)雜的查詢操作是完成不了。 ORM用多了SQL語(yǔ)句就不會(huì)寫(xiě)了存炮,關(guān)系數(shù)據(jù)庫(kù)相關(guān)技能退化…
- ORM 總結(jié)
ORM只是一種工具炬搭,工具確實(shí)能解決一些重復(fù),簡(jiǎn)單的勞動(dòng)穆桂。這是不可否認(rèn)的宫盔。 但我們不能指望某個(gè)工具能一勞永逸地解決所有問(wèn)題,一些特殊問(wèn)題還是需要特殊處理的享完。 但是在整個(gè)軟件開(kāi)發(fā)過(guò)程中需要特殊處理的情況應(yīng)該都是很少的灼芭,否則所謂的工具也就失去了它存在的意義。
- ORM 與 DB 的對(duì)應(yīng)關(guān)系
ORM 面向?qū)ο蠛完P(guān)系型數(shù)據(jù)庫(kù)的一種映射,通過(guò)操作對(duì)象的方式操作數(shù)據(jù)庫(kù)數(shù)據(jù),不支持對(duì)庫(kù)的操作,只能操作表 對(duì)應(yīng)關(guān)系: 類 --> 表 對(duì)象 --> 數(shù)據(jù)行 屬性 --> 字段
Model 模塊 在Django中model是你數(shù)據(jù)的單一般又、明確的信息來(lái)源彼绷。它包含了你存儲(chǔ)的數(shù)據(jù)的重要字段和行為。通常茴迁, 一個(gè)模型(model)映射到一個(gè)數(shù)據(jù)庫(kù)表寄悯。
- 基本情況:
每個(gè)模型都是一個(gè)Python類,它是django.db.models.Model的子類堕义。模型的每個(gè)屬性都代表一個(gè)數(shù)據(jù)庫(kù)字段猜旬。
綜上所述,Django為您提供了一個(gè)自動(dòng)生成的數(shù)據(jù)庫(kù)訪問(wèn)API,詳詢官方文檔
1. 安裝mysql
- 安裝歷史版本5.7的
- 參考:http://www.reibang.com/p/56e965f90b7d 中安裝mysql部分(mac安裝)
2. django連接配置數(shù)據(jù)庫(kù)
mysql中新建一個(gè)數(shù)據(jù)庫(kù)
-
安裝msyql client
pip install mysqlclient==1.4.6
-
settings.py文件中配置數(shù)據(jù)庫(kù)鏈接信息
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '127.0.0.1', # 數(shù)據(jù)庫(kù)主機(jī) 'PORT': 3306, # 數(shù)據(jù)庫(kù)端口 'USER': 'root', # 數(shù)據(jù)庫(kù)用戶名 'PASSWORD': 'root', # 數(shù)據(jù)庫(kù)用戶密碼 'NAME': 'test' # 數(shù)據(jù)庫(kù)名字 } }
-
檢查是否配置成功
- pycharm terminal中執(zhí)行python manage.py dbshell
- 可進(jìn)入mysql虛擬終端洒擦,表示配置成功
3. ORM表模型
定義模型
在Django中椿争,所有的模型必須繼承from django.db.models import Model
這個(gè)類,字段類型需要使用models模塊中定義好的字段類型
from django.db import models
class Student(models.Model): # 一個(gè)類對(duì)應(yīng)一個(gè)表
# 類屬性對(duì)應(yīng)表中的字段秘遏,models.CharField這里對(duì)應(yīng)字段的類型丘薛,這個(gè)是字符串類型
# max_length定義字段的最大長(zhǎng)度
# 五大約束:非空約束(null=False,為默認(rèn),可不寫(xiě))、主鍵約束(primary_key=True)邦危、唯一約束(unique=True)洋侨、可空(null=True)、外鍵約束(通過(guò)models.ForeignKey()來(lái)指定)
# help_text添加該字段的備注信息倦蚪,但沒(méi)有加在數(shù)據(jù)庫(kù)中希坚,讓自己看著比較清楚
# choices=((0, '男'), (1, '女')),表示該字段只有0陵且,1兩個(gè)值裁僧,0代表男,1代表女
# models.DateTimeField 該字段是日期類型
# auto_now_add=True 在每一次數(shù)據(jù)被添加進(jìn)去的時(shí)候慕购,記錄當(dāng)前時(shí)間
# auto_now=True 在每一次數(shù)據(jù)被保存的時(shí)候聊疲,記錄當(dāng)前時(shí)間
s_name = models.CharField(max_length=64,help_text="學(xué)生姓名")
s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性別")
s_phone = models.CharField(max_length=11, help_text="手機(jī)號(hào)")
create_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'student' # 指定表名,如果不指定表名沪悲,會(huì)用app名+類名生成表名
下圖是mysql數(shù)據(jù)庫(kù)字段和Models中定義類型的關(guān)系
模型中常用屬性
django提供的一些特殊屬性
EmailField(CharField):
- 字符串類型获洲,Django Admin以及ModelForm中提供驗(yàn)證機(jī)制
- e_mail = models.EmailField(max_length=255, unique=True)
IPAddressField(Field)
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 IPV4 機(jī)制
GenericIPAddressField(Field)
- 字符串類型殿如,Django Admin以及ModelForm中提供驗(yàn)證 Ipv4和Ipv6
- 參數(shù):
protocol贡珊,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4涉馁, 如果指定為T(mén)rue门岔,則輸入::ffff:192.0.2.1時(shí)候,可解析為192.0.2.1烤送,開(kāi)啟此功能寒随,需要protocol="both"
URLField(CharField)
- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 URL
SlugField(CharField)
- 字符串類型帮坚,Django Admin以及ModelForm中提供驗(yàn)證支持 字母牢裳、數(shù)字、下劃線叶沛、連接符(減號(hào))
CommaSeparatedIntegerField(CharField)
- 字符串類型蒲讯,格式必須為逗號(hào)分割的數(shù)字
UUIDField(Field)
- 字符串類型,Django Admin以及ModelForm中提供對(duì)UUID格式的驗(yàn)證
FilePathField(Field)
- 字符串灰署,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
- 參數(shù):
path, 文件夾路徑
match=None, 正則匹配
recursive=False, 遞歸下面的文件夾
allow_files=True, 允許文件
allow_folders=False, 允許文件夾
FileField(Field)
- 字符串判帮,路徑保存在數(shù)據(jù)庫(kù)局嘁,文件上傳到指定目錄
- 參數(shù):
upload_to = "" 上傳文件的保存路徑
storage = None 存儲(chǔ)組件携茂,默認(rèn)django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串务荆,路徑保存在數(shù)據(jù)庫(kù),文件上傳到指定目錄
- 參數(shù):
upload_to = "" 上傳文件的保存路徑
storage = None 存儲(chǔ)組件纯丸,默認(rèn)django.core.files.storage.FileSystemStorage
width_field=None, 上傳圖片的高度保存的數(shù)據(jù)庫(kù)字段名(字符串)
height_field=None 上傳圖片的寬度保存的數(shù)據(jù)庫(kù)字段名(字符串)
自定義字段(了解即可)
示例:我們發(fā)現(xiàn)上邊沒(méi)有固定長(zhǎng)度的字符串類型晌畅,但是手機(jī)號(hào)字段一般都是定長(zhǎng)11位的字符串但指,所以我們需要自定義一些字段類型
from django.db import models
# Create your models here.
class PhoneField(models.Field): # 自定義的char類型的字段類
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(PhoneField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection): # 限定生成數(shù)據(jù)庫(kù)表的字段類型為char,長(zhǎng)度為max_length指定的值的字符串
return 'char(%s)' % self.max_length
Field的常用參數(shù)
模型中Meta配置:
對(duì)于一些模型級(jí)別的配置抗楔。我們可以在模型中定義一個(gè)類棋凳,叫做Meta。然后在這個(gè)類中添加一些類屬性來(lái)控制模型的作用连躏。
比如我們想要在數(shù)據(jù)庫(kù)映射的時(shí)候使用自己指定的表名剩岳,而不是使用模型的名稱。那么我們可以在Meta類中添加一個(gè)db_table的屬性入热。示例代碼如下:
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
class Meta:
db_table = 'book_model'
外鍵和表關(guān)系
4. ORM模型遷移
生成遷移腳本
python manage.py makemigrations
![image](https://upload-images.jianshu.io/upload_images/12041448-8322b9155e8bc7fa?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
會(huì)在model_demo下的migrations文件夾下生成一個(gè)
0001_initial.py
文件,如下:from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Student', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('s_name', models.CharField(help_text='學(xué)生姓名', max_length=64)), ('s_sex', models.IntegerField(choices=[(0, '男'), (1, '女')], help_text='性別')), ('s_phone', models.CharField(help_text='手機(jī)號(hào)', max_length=11)), ('create_time', models.DateTimeField(auto_now_add=True)), ('update_time', models.DateTimeField(auto_now=True)), ], options={ 'db_table': 'student', }, ), ]
比我們自己寫(xiě)的model,多了一個(gè)id字段拍棕,這是django自動(dòng)生成的,對(duì)所有的表都會(huì)添加這樣一個(gè)字段勺良,所以不用特別去定義绰播。
遷移腳本生成時(shí),數(shù)據(jù)庫(kù)還沒(méi)有這個(gè)表尚困。
執(zhí)行遷移標(biāo)本蠢箩,數(shù)據(jù)庫(kù)中創(chuàng)建新表
python manage.py migrate
因?yàn)橹斑€做了別的操作,只想執(zhí)行model_demo下的遷移腳本尾组,所以可以在命令后面加上app的名字忙芒。
在數(shù)據(jù)庫(kù)中創(chuàng)建了student表示弓,django_migrations表存儲(chǔ)了的是django的遷移記錄讳侨。
可以看看這些字段的約束和我們定義的一樣:
遷移命令詳解
-
makemigrations:將模型生成遷移腳本。模型所在的app奏属,必須放在settings.py中的INSTALLED_APPS中跨跨。這個(gè)命令有以下幾個(gè)常用選項(xiàng):
app_label:后面可以跟一個(gè)或者多個(gè)app,那么就只會(huì)針對(duì)這幾個(gè)app生成遷移腳本囱皿。如果沒(méi)有任何的app_label勇婴,那么會(huì)檢查INSTALLED_APPS中所有的app下的模型,針對(duì)每一個(gè)app都生成響應(yīng)的遷移腳本嘱腥。
-name:給這個(gè)遷移腳本指定一個(gè)名字耕渴。
-empty:生成一個(gè)空的遷移腳本。如果你想寫(xiě)自己的遷移腳本齿兔,可以使用這個(gè)命令來(lái)實(shí)現(xiàn)一個(gè)空的文件橱脸,然后自己再在文件中寫(xiě)遷移腳本础米。
-
migrate:將新生成的遷移腳本。映射到數(shù)據(jù)庫(kù)中添诉。創(chuàng)建新的表或者修改表的結(jié)構(gòu)屁桑。以下一些常用的選項(xiàng):
- app_label:將某個(gè)app下的遷移腳本映射到數(shù)據(jù)庫(kù)中。如果沒(méi)有指定栏赴,那么會(huì)將所有在INSTALLED_APPS中的app下的模型都映射到數(shù)據(jù)庫(kù)中蘑斧。
app_label migrationname:將某個(gè)app下指定名字的migration文件映射到數(shù)據(jù)庫(kù)中。 - –fake:可以將指定的遷移腳本名字添加到數(shù)據(jù)庫(kù)中须眷。但是并不會(huì)把遷移腳本轉(zhuǎn)換為SQL語(yǔ)句竖瘾,修改數(shù)據(jù)庫(kù)中的表。
- –fake-initial:將第一次生成的遷移文件版本號(hào)記錄在數(shù)據(jù)庫(kù)中柒爸。但并不會(huì)真正的執(zhí)行遷移腳本准浴。
- app_label:將某個(gè)app下的遷移腳本映射到數(shù)據(jù)庫(kù)中。如果沒(méi)有指定栏赴,那么會(huì)將所有在INSTALLED_APPS中的app下的模型都映射到數(shù)據(jù)庫(kù)中蘑斧。
showmigrations:查看某個(gè)app下的遷移文件。如果后面沒(méi)有app捎稚,那么將查看INSTALLED_APPS中所有的遷移文件乐横。
sqlmigrate:查看某個(gè)遷移文件在映射到數(shù)據(jù)庫(kù)中的時(shí)候,轉(zhuǎn)換的SQL語(yǔ)句今野。
5. abstract創(chuàng)建模型父類
在創(chuàng)建模型的時(shí)候葡公,其實(shí)有好多字段都是模型中共同存在的,例如createtime,updatetime,mark等等条霜,這些字段我們需要在每個(gè)模型中重復(fù)創(chuàng)建催什,這就造成了工作量的浪費(fèi),我們可以通過(guò)創(chuàng)建一個(gè)公共的模型父類來(lái)宰睡,子類集成該父類蒲凶,這樣我們就不需要重復(fù)寫(xiě)這些字段了
class PublicModel(models.Model):
createtime = models.DateTimeField(auto_now_add=True,verbose_name="創(chuàng)建日期")
updatetime = models.DateTimeField(auto_now=True,verbose_name = '修改日期')
status = models.IntegerField(verbose_name = '狀態(tài)')
class Meta:
abstract=True # 父類中必須指定該屬性,否則該類會(huì)被創(chuàng)建到數(shù)據(jù)庫(kù)
# 子類繼承PublicModel類拆内,就不需要重復(fù)寫(xiě)createtime,update,status三個(gè)字段的定義了
class Student(PublicModel):
s_name = models.CharField(max_length=64,help_text="學(xué)生姓名")
s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性別")
s_phone = models.CharField(max_length=11, help_text="手機(jī)號(hào)")
class Meta:
db_table = 'student'
- model修改旋圆,重新遷移
- 刪掉migrations文件夾下遷移腳本
- 刪掉django_migrations表中的遷移記錄
- 刪掉student表
- 重新生成遷移腳本
- 執(zhí)行遷移腳本
6. ORM操作
ORM操作準(zhǔn)備
-
以這個(gè)模型來(lái)進(jìn)行后續(xù)的ORM操作練習(xí)
class Student(models.Model): s_name = models.CharField(max_length=64,help_text="學(xué)生姓名") s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性別") s_phone = models.CharField(max_length=11, help_text="手機(jī)號(hào)") create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True) class Meta: db_table = 'student'
-
進(jìn)入django的虛擬終端
-
導(dǎo)入要操作的模型類
新增數(shù)據(jù)
- 插入單條數(shù)據(jù)-save
s = Student(s_name="李白",s_sex=0,s_phone='18103909786') s.save()
![image](https://upload-images.jianshu.io/upload_images/12041448-51f8e1f7d480c0a8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
數(shù)據(jù)庫(kù)新增了一條記錄:
![image](https://upload-images.jianshu.io/upload_images/12041448-294c9a2b6642c6f2?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
插入單條數(shù)據(jù)-create
使用模型對(duì)象(objects)操作數(shù)據(jù)庫(kù)
Student.objects.create(s_name='魯班七號(hào)',s_sex=0,s_phone='15855586589')
數(shù)據(jù)庫(kù)新增了一條記錄:
-
批量插入多條數(shù)據(jù)-bulk_create
s1 = Student(s_name="王二錘",s_sex=0,s_phone='18103909782') s2 = Student(s_name="王三錘",s_sex=0,s_phone='18103909783') s3 = Student(s_name="王四錘",s_sex=0,s_phone='18103909784') student_list = [s1,s2,s3] Student.objects.bulk_create(student_list)
數(shù)據(jù)庫(kù)新增了多條數(shù)據(jù):
查找數(shù)據(jù)
查找數(shù)據(jù)都是通過(guò)模型下的objects對(duì)象來(lái)實(shí)現(xiàn)的
-
查找所有數(shù)據(jù)
使用
Student.objects.all()
student表的所有數(shù)據(jù),等同于select * from student
通過(guò)上邊的例子我們可看出麸恍,我們使用Student.objects.all()方法查詢出了數(shù)據(jù)所有的數(shù)據(jù)灵巧,返回了一個(gè)QuerySet的list對(duì)象,list里邊存的都是Student對(duì)象抹沪,所以我們可以通過(guò)students[0]拿到list中第一個(gè)Student對(duì)象刻肄,然后通過(guò)Student.s_name就可以查看Student對(duì)象中,s_name的值同理融欧,我們可以用類似的方法查看s_sex,s_phone的值
數(shù)據(jù)過(guò)濾
-
單條件過(guò)濾
在查找數(shù)據(jù)的時(shí)候敏弃,有時(shí)候需要對(duì)一些數(shù)據(jù)進(jìn)行過(guò)濾。那么這時(shí)候需要調(diào)用objects的
filter
方法噪馏。類似與sql語(yǔ)句中的where麦到,查詢出s_name='魯班七號(hào)'的數(shù)據(jù)虹茶,返回的是一個(gè)list,所以需要加上下標(biāo)訪問(wèn)隅要。
搜索出來(lái)的結(jié)果返回是一個(gè)QuerySet蝴罪,QuerySet常用的內(nèi)置方法
values()
、first()
![image](https://upload-images.jianshu.io/upload_images/12041448-6a67a6b89e507f30?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
`values()`展示詳細(xì)的數(shù)據(jù)步清,更易讀
`first()` 展示第一條數(shù)據(jù)
-
其他過(guò)濾條件(雙下劃線查詢)
# 查詢姓名中包含'二'字的學(xué)生信息 s = Student.objects.filter(s_name__contains='王') s[0].s_name # 查詢id>2的學(xué)生信息 s=Student.objects.filter(id__gt=2).values() s
![image](https://upload-images.jianshu.io/upload_images/12041448-92b1ad44c8ac97fe?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
常用的符號(hào)
![image](https://upload-images.jianshu.io/upload_images/12041448-b2798ac9c8f03abb?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
日期過(guò)濾
settings.py文件中修改
USE_TZ = False
# 查詢?nèi)掌谑?020-07-05創(chuàng)建的用戶 s=Student.objects.filter(create_time__date='2020-07-05')
-
日期的比較
# 查詢2020-07-05 00:00:00之后創(chuàng)建的用戶 import datetime date = datetime.datetime(2020,4,2) student = Student.objects.filter(create_time__gte=date)
其他查詢方式
-
get查詢
獲取滿足條件的一個(gè)數(shù)據(jù)要门,獲取不到或者多個(gè)都報(bào)錯(cuò)。一般通過(guò)主鍵查詢廓啊。
s = Student.objects.get(pk=1)
欢搜,pk就是主鍵的意思,可以看到get方法返回的是一個(gè)Student對(duì)象 -
exclude
獲取不滿足條件的所有數(shù)據(jù)谴轮,exclude返回的是一個(gè)QuerySet類型的對(duì)象列表
# 獲取主鍵不等于1的所有數(shù)據(jù) s = Student.objects.exclude(pk=1)
-
values
查詢的對(duì)象轉(zhuǎn)為字典炒瘟。
s = Student.objects.exclude(pk=1) # 先根據(jù)條件篩選出部分?jǐn)?shù)據(jù),返回結(jié)果是一個(gè)QuerySet類型的對(duì)象列表 s.values('s_name','s_sex') # 再使用values()確定展示字段 Student.objects.values('s_name','s_sex') # #查詢出全部數(shù)據(jù)第步,并確定展示字段
-
values_list()
它與values()非常相似疮装,它返回的是一個(gè)元組序列,相對(duì)字典要節(jié)省空間粘都。
Student.objects.values_list('s_name','s_sex')
-
first
取第一條元素廓推。沒(méi)有元素返回None,有返回第一條記錄翩隧。相當(dāng)于
Student.objects.exclude(pk=1)[0]
樊展,但是Student.objects.exclude(pk=1)[0]
沒(méi)有值時(shí)會(huì)報(bào)錯(cuò)。Student.objects.exclude(pk=1).first()
-
last
取最后一條元素堆生。沒(méi)有元素返回None专缠,有返回最后一條記錄。與first同理
Student.objects.exclude(pk=1).last()
-
exists
如果QuerySet包含數(shù)據(jù)淑仆,就返回True涝婉,否則返回False
Student.objects.filter(pk=1).exists()
-
嵌套查詢
-- 查詢性別和id=2的學(xué)生相同的所有學(xué)生信息 SELECT * from student where s_sex in (SELECT s_sex from student where id=2)
ORM實(shí)現(xiàn):
student=Student.objects.filter(pk=2) Student.objects.filter(s_sex=student[0].s_sex)
![image](https://upload-images.jianshu.io/upload_images/12041448-a93aa961db53fe28?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
F查詢
(針對(duì)自己?jiǎn)伪碇凶侄蔚谋容^和處理)
在上面所有的例子中,我們構(gòu)造的過(guò)濾器都只是將字段值與某個(gè)常量做比較糯景。如果我們要對(duì)兩個(gè)字段的值做比較嘁圈,那該怎么做呢省骂?
# 查詢創(chuàng)建之后被修改了的用戶信息 from django.db.models import F Student.objects.filter(update_time__gt=F("create_time"))
多條件查詢
-
并列關(guān)系
filter默認(rèn)就是并列關(guān)系,逗號(hào)分割就是并列關(guān)系
Student.objects.filter(s_name='魯班七號(hào)',s_sex=0)
-
Q查詢
使用Q查詢蟀淮,先要導(dǎo)入Q查詢模塊
from django.db.models import Q
-
與
&
stu=Student.objects.filter(Q(s_name='魯班七號(hào)')&Q(s_sex=0))
-
- 或 `|`
```
# 篩選s_name='魯班七號(hào)'或者s_sex=1
stu=Student.objects.filter(Q(s_name='魯班七號(hào)')|Q(s_sex=1))
```
![image](https://upload-images.jianshu.io/upload_images/12041448-05954b20d16bdd4c?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 非 `~`
```
stu=Student.objects.filter(~Q(s_sex=0))
```
![image](https://upload-images.jianshu.io/upload_images/12041448-502a2ec8d476aa90?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
數(shù)據(jù)聚合-aggregate
sql中聚合函數(shù)有:max()、min()钞澳、count()怠惶、avg()、sum(),在ORM中如何表示轧粟?
使用聚合函數(shù)對(duì)數(shù)據(jù)進(jìn)行統(tǒng)計(jì)操作策治,就需要使用到aggregate方法,返回的是一個(gè)字典脓魏。
aggregate是從整個(gè)查詢結(jié)果集生成統(tǒng)計(jì)數(shù)據(jù)。
-
導(dǎo)入聚合函數(shù)的類
from django.db.models import Avg, Sum, Max, Min, Count
-
用法:先篩選通惫,再聚合
-
修改字段名
排序
排序使用order_by()
# 按id字段正序排列茂翔,默認(rèn)為正序,由小到大
stu=Student.objects.filter(Q(s_name='魯班七號(hào)')|Q(s_sex=0)).order_by("id")
# 按id字段倒序排列履腋,加個(gè)符號(hào)
stu=Student.objects.filter(Q(s_name='魯班七號(hào)')|Q(s_sex=0)).order_by("-id")
數(shù)據(jù)去重
去重使用.valuse("去重字段").distinct
# s_sex字段去重
stu=Student.objects.filter(s_sex=0).values("s_sex").distinct()
分頁(yè)
使用django自帶的分頁(yè)器Paginator來(lái)對(duì)數(shù)據(jù)進(jìn)行分頁(yè)操作
-
導(dǎo)入分頁(yè)器
from django.core.paginator import Paginator
-
分頁(yè)
# 導(dǎo)入模塊 from django.core.paginator import Paginator # Paginator第一個(gè)參數(shù)是要分頁(yè)的數(shù)據(jù)珊燎,第二個(gè)參數(shù)per_page是每頁(yè)的數(shù)據(jù)條數(shù) p = Paginator(Student.objects.all(),per_page=2) # get_page()表示獲取第幾頁(yè)的數(shù)據(jù),返回一個(gè)Page對(duì)象遵湖,object_list獲取對(duì)象中的數(shù)據(jù)列表 print(p.get_page(1).object_list)
當(dāng)獲取的頁(yè)數(shù)悔政,沒(méi)有數(shù)據(jù)時(shí),會(huì)返回最后一頁(yè)的數(shù)據(jù)延旧。
# 判斷是否有下一頁(yè),有下一頁(yè)返回True谋国,沒(méi)有返回False p.page(1).has_next()
# 判斷是否有前一頁(yè) p.page(1).has_previous()
其他的一些分頁(yè)操作:
分組
-
sq中的分組
select s_sex,count(*) from student group by s_sex;
sql中的分組有語(yǔ)法約定,展示的字段迁沫,只能是被分組的字段和聚合函數(shù)芦瘾。
在ORM中,我們也是重點(diǎn)關(guān)注集畅,
展示字段
和分組字段
-
ORM的分組
Student.objects.all().values('s_sex').annotate(Count('id')).values('s_sex','id__count')
第一個(gè)
.values('s_sex')
是確定分組的字段旅急,annotate(Count('id'))
是聚合函數(shù),.values('s_sex','id__count')
是展示字段牡整,回想之前學(xué)習(xí)Count時(shí)藐吮,count('id'),返回的字段是id__count
,所以這里展示字段要寫(xiě)id__count
![image](https://upload-images.jianshu.io/upload_images/12041448-a9aed20f130328f8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
所以,它還可以這樣寫(xiě)逃贝,使用`count=Count('id')`
```
Student.objects.all().values('s_sex').annotate(count=Count('id')).values('s_sex','count')
```
![image](https://upload-images.jianshu.io/upload_images/12041448-5221b6a94c135025?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
having怎么實(shí)現(xiàn)
在annotate之后使用filter谣辞,相當(dāng)于having
Student.objects.all().values('s_sex').annotate(count=Count('id')).filter(count=1).values('s_sex')
修改數(shù)據(jù)
get和filter查詢出來(lái)的數(shù)據(jù)結(jié)構(gòu)不一樣,get查詢出來(lái)的結(jié)果是一個(gè)對(duì)象沐扳,filter泥从、exclude等查詢出來(lái)的結(jié)果是一個(gè)查詢集,他們的修改操作是不一樣的沪摄。
-
對(duì)對(duì)象的修改操作
# 把id=3的性別改為1 stu=Student.objects.get(id=3) # stu是一個(gè)對(duì)象 stu.s_sex=1 # 修改對(duì)象中的屬性值躯嫉,此時(shí),數(shù)據(jù)庫(kù)值還沒(méi)有改變 stu.save() # 使用.save()來(lái)觸發(fā)對(duì)數(shù)據(jù)庫(kù)的操作
-
對(duì)查詢集的修改操作
# 把性別為1的學(xué)生手機(jī)號(hào)改為13800000000 student=Student.objects.filter(s_sex=1) # student是一個(gè)查詢集 student.update(s_phone='13800000000') # 使用.update()來(lái)修改值 # 修改多個(gè)值使用逗號(hào)分割 student.update(s_phone='13800000000',s_name='王小二')
刪除數(shù)據(jù)
在查找到數(shù)據(jù)后杨拐,便可以進(jìn)行刪除了祈餐。刪除數(shù)據(jù)非常簡(jiǎn)單,只需要調(diào)用這個(gè)對(duì)象的delete方法即可哄陶。
stu = Student.objects.get(id='6')
stu.delete()
-
物理刪除&邏輯刪除
事務(wù)和回滾
-
什么是事務(wù)和回滾
事務(wù):多個(gè)數(shù)據(jù)邏輯操作的集合
回滾:多個(gè)邏輯中某個(gè)操作出錯(cuò)帆阳,回到初始狀態(tài)
事務(wù)的原子性要求事務(wù)要么全部完成,要么全部不完成屋吨,不可能停滯在某個(gè)中間狀態(tài)
-
什么情況下需要使用事務(wù)
修改多個(gè)ORM模型做時(shí)需要使用事務(wù)和回滾操作
對(duì)結(jié)果要求嚴(yán)格一致(要么全部成功蜒谤,要么全部失斏奖觥)
-
django中怎么使用事務(wù)
- 自動(dòng)進(jìn)行事務(wù)提交和回滾
# 自動(dòng)進(jìn)行事務(wù)提交和回滾 from django.db import transaction # 使用@transaction.atomic實(shí)現(xiàn)自動(dòng)進(jìn)行事務(wù)提交和回滾 @transaction.atomic def test(request): # 事務(wù)提交 Student.objects.filter(id=1).update(s_sex=1) # 若沒(méi)有事務(wù),這次操作是會(huì)成功的 stu = Student.objects.get(id=0) # 查詢不到id=0的學(xué)生鳍徽,get方法會(huì)報(bào)錯(cuò) stu.s_sex=1 stu.save() Student.objects.filter(id=2).update(s_sex=1)# 失敗 return HttpResponse("ok") def test(request): # 使用上下文管理器實(shí)現(xiàn)自動(dòng)進(jìn)行事務(wù)提交和回滾 with transaction.atomic(): Student.objects.get(id=1).update(s_sex=1) # 若沒(méi)有事務(wù)资锰,這次操作是會(huì)成功的 stu = Student.objects.get(id=0) # 查詢不到id=0的學(xué)生,get方法會(huì)報(bào)錯(cuò) stu.s_sex=1 stu.save() Student.objects.filter(id=2).update(s_sex=1)# 失敗 return HttpResponse("ok")
- 手動(dòng)進(jìn)行事務(wù)提交和回滾
# 手動(dòng)進(jìn)行事務(wù)提交和回滾 def test(request): # 事務(wù)提交 try: transaction.set_autocommit(False)# 關(guān)閉django自動(dòng)提交 Student.objects.get(id=1).update(s_sex=1) # 若沒(méi)有事務(wù)阶祭,這次操作是會(huì)成功的 stu = Student.objects.get(id=0) # 查詢不到id=0的學(xué)生台妆,get方法會(huì)報(bào)錯(cuò) stu.s_sex=1 stu.save() Student.objects.filter(id=2).update(s_sex=1)# 失敗 transaction.commit() # 操作成功,事務(wù)提交 except: print("操作失敗胖翰,事務(wù)回滾") transaction.rollback() # 操作失敗接剩,事務(wù)回滾 return HttpResponse("ok")
- 自動(dòng)進(jìn)行事務(wù)提交和回滾
7. ORM多表關(guān)聯(lián)
關(guān)聯(lián)關(guān)系
-
一對(duì)一
student <----> student_info
-
多對(duì)一
score --------> student
score --------> course
course --------> teacher
-
多對(duì)多
student <----------------------> course
關(guān)聯(lián)模型創(chuàng)建
-
一對(duì)一
models.OneToOneField()
關(guān)聯(lián)關(guān)系放在使用頻率較高的表
-
多對(duì)一
models.ForeignKey()
關(guān)聯(lián)關(guān)放在“多”的表里
-
多對(duì)多
models.ManyToManyField()
關(guān)聯(lián)關(guān)放在使用頻率較高的表
![image](https://upload-images.jianshu.io/upload_images/12041448-9c7c7f28130527bb?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
關(guān)系表級(jí)聯(lián)刪除
on_delete
代碼示例
models.py
from django.db import models
# Create your models here.
# 學(xué)生表
class Stu(models.Model):
s_name = models.CharField('學(xué)生姓名', max_length=64, null=False, help_text='學(xué)生姓名')
s_sex = models.IntegerField('性別', max_length=1, choices=((0, '男'), (1, '女')), help_text='性別')
s_age = models.PositiveIntegerField('年齡', null=False, default=0, help_text='年齡')
s_dept = models.CharField("專業(yè)", max_length=64, null=False, help_text="專業(yè)")
# 一對(duì)一關(guān)系,用models.OneToOneField(),關(guān)聯(lián)放在使用頻率較高的表中
"""
models.OneToOneField()有三個(gè)參數(shù):
to:設(shè)置要關(guān)聯(lián)的表名(類),
to_field:設(shè)置要關(guān)聯(lián)的表字段(類屬性),
on_delete:當(dāng)關(guān)聯(lián)字段刪除時(shí)萨咳,s_id的值設(shè)置成什么懊缺,常用設(shè)置為models.CASCADE,表示當(dāng)關(guān)聯(lián)字段刪除時(shí)培他,它也刪除
"""
"""
related_name:一般可以使用當(dāng)前表_關(guān)聯(lián)表來(lái)命名
正向查詢時(shí)鹃两,通過(guò)s_id可以查詢student_info表中的數(shù)據(jù),
反向查詢(從student_info表查詢student表數(shù)據(jù)時(shí))使用related_name進(jìn)行查詢
"""
# db_column指定表字段列名
si_id = models.OneToOneField(to='StudentInfo', to_field="id", on_delete=models.CASCADE, db_column='si_id',
related_name="stu_stu_info")
# 多對(duì)多關(guān)系會(huì)自動(dòng)生成一張中間表舀凛,db_table是對(duì)中間表的命名
course = models.ManyToManyField(to="Course", db_table="stu_course", related_name="course_student")
class Meta:
db_table = 'stu'
# 學(xué)生信息表
class StudentInfo(models.Model):
s_card = models.CharField("身份證號(hào)", max_length=18, null=False, unique=True)
s_phone = models.CharField(max_length=11, null=False, unique=True, help_text="手機(jī)號(hào)")
s_addr = models.CharField("家庭住址", max_length=128, help_text="家庭住址")
class Meta:
db_table = "student_info"
# 課程表
class Course(models.Model):
c_name = models.CharField('課程名',max_length=64,null=False,help_text="課程名")
t_id = models.ForeignKey(to="Teacher",to_field="id",on_delete=models.CASCADE,related_name='teacher_course',db_column='t_id',help_text="老師編號(hào)")
class Meta:
db_table="course"
# 成績(jī)表
class Score(models.Model):
s_id = models.ForeignKey(to="Stu", to_field="id", on_delete=models.CASCADE, related_name='stu_score',
db_column='s_id', help_text="學(xué)生編號(hào)")
c_id = models.ForeignKey(to="Course", to_field="id", on_delete=models.CASCADE, related_name='course_score',
db_column='c_id', help_text="學(xué)生編號(hào)")
score = models.PositiveIntegerField("成績(jī)",null=False,default=0,help_text="成績(jī)")
class Meta:
db_table = "score"
# 老師表
class Teacher(models.Model):
t_name = models.CharField("老師姓名", max_length=64,null=False,help_text="老師姓名")
class Meta:
db_table = "teacher"
數(shù)據(jù)遷移:
python manage.py makemigrations
python manage.py migrate multi_table
關(guān)聯(lián)模型操作
增刪改俊扳,都是單表操作,只有查詢涉及多表猛遍,我們就主要講下查詢的多表操作
-
數(shù)據(jù)準(zhǔn)備
-- 數(shù)據(jù)準(zhǔn)備sql insert into `student_info` (`id`, `s_card`, `s_phone`, `s_addr`) values('1','410422200205061358','18103909786','河南省魯山縣'); insert into `student_info` (`id`, `s_card`, `s_phone`, `s_addr`) values('2','310112199003074772','13853444534','上海閔行區(qū)'); insert into `student_info` (`id`, `s_card`, `s_phone`, `s_addr`) values('3','31011520020907641X','15520979867','上海市浦東新區(qū)'); insert into `stu` (`id`, `s_name`, `s_sex`, `s_age`, `s_dept`, `si_id`) values('2','薛小磊','0','18','計(jì)算機(jī)科學(xué)','1'); insert into `stu` (`id`, `s_name`, `s_sex`, `s_age`, `s_dept`, `si_id`) values('3','王大錘','1','30','生物科學(xué)','2'); insert into `stu` (`id`, `s_name`, `s_sex`, `s_age`, `s_dept`, `si_id`) values('4','薛大磊','0','18','外貿(mào)金融','3'); insert into `teacher` (`id`, `t_name`) values('1','張三'); insert into `teacher` (`id`, `t_name`) values('2','李四'); insert into `teacher` (`id`, `t_name`) values('3','王五'); insert into `course` (`id`, `c_name`, `t_id`) values('1','數(shù)學(xué)','1'); insert into `course` (`id`, `c_name`, `t_id`) values('2','語(yǔ)文','2'); insert into `course` (`id`, `c_name`, `t_id`) values('3','英語(yǔ)','3'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('1','80','1','2'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('2','90','2','2'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('3','85','3','2'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('4','60','1','3'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('5','55','2','3'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('6','70','3','3'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('7','30','1','4'); insert into `score` (`id`, `score`, `c_id`, `s_id`) values('8','50','2','4');
tips:當(dāng)模型改變時(shí)馋记,需要刷新一下Python Console
-
新增數(shù)據(jù)
學(xué)生表和中間表stu_course是多對(duì)多的關(guān)系,中間表是django自動(dòng)生成的懊烤,是沒(méi)有數(shù)據(jù)的梯醒。中間表的數(shù)據(jù),只能通過(guò)一張表來(lái)生成另一張表的數(shù)據(jù)腌紧,我們從stu表生成stu_course表的數(shù)據(jù)茸习。
# 查詢出一條數(shù)據(jù),返回結(jié)果是Stu對(duì)象 stu = Stu.objects.filter(s_name='薛小磊').first() # 使用add方法往第三張表中添加三條和薛小磊關(guān)聯(lián)的數(shù)據(jù)壁肋,`.course`是字段名 # 通過(guò)stu_id增加course_id号胚,stu_id=2的學(xué)生,選了3門(mén)課浸遗,課程id是1猫胁,2,3 stu.course.add(1,2,3) # stu_id為3的學(xué)生乙帮,選了課程id是2杜漠,3的兩門(mén)課 Stu.objects.get(pk=3).course.add(2,3) Stu.objects.get(pk=4).course.add(1,2)
-
刪除數(shù)據(jù)
# 查詢出一條數(shù)據(jù) stu = Stu.objects.filter(s_name='薛小磊').first() # 使用remove方法刪除中間表中的和薛小磊關(guān)聯(lián)的數(shù)據(jù) stu.course.remove(1,2,3)
-
重置數(shù)據(jù)
#無(wú)則加极景,有則刪除 stu = Stu.objects.filter(s_name='薛小磊').first() # 添加編號(hào)2 3的選課記錄 stu.course.add(2, 3) # 使用set方法重置選課記錄為1,3 stu = Stu.objects.filter(s_name='薛小磊').first() stu.course.set([1,3])
-
清空
# 清空薛小磊所有的選課記錄 stu = Stu.objects.filter(s_name='薛小磊').first() stu.course.clear()
-
一對(duì)一查詢
# 導(dǎo)入model from multi_table.models import Stu from multi_table.models import StudentInfo
# 正向查詢:關(guān)聯(lián)student_info表查詢第一條學(xué)生的身份證號(hào) student=Stu.objects.first() stu_detail=student.si_id stu_detail.s_card
# 反向查詢:查詢身份證號(hào)為410422200205061358的學(xué)生姓名 stu_info=StudentInfo.objects.filter(s_card='410422200205061358').first() stu=stu_info.stu_stu_info # 通過(guò)related_name進(jìn)行反向查詢 stu.s_name
-
多對(duì)一查詢
# 導(dǎo)入model from multi_table.models import Course from multi_table.models import Teacher
# 正向查詢:通過(guò)課程表查找任課老師 course=Course.objects.filter(c_name='語(yǔ)文').first() teacher=course.t_id teacher.t_name
# 反向查詢 # 通過(guò)通過(guò)related_name進(jìn)行反向查詢察净,course返回了一個(gè)model的對(duì)象 course=Teacher.objects.first().teacher_course # 對(duì)象轉(zhuǎn)為查詢集 courses=course.all() # 通過(guò)for循環(huán)編輯結(jié)果 for c in courses: print(c.c_name)
![image](https://upload-images.jianshu.io/upload_images/12041448-80e0c140a41b85fe?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
多對(duì)多
# 多對(duì)多正向查詢- 根據(jù)屬性course查詢 # 查詢 薛小磊同學(xué)選修的課程名 stu = Stu.objects.filter(s_name='薛小磊').first() courses = stu.course.all() for c in courses: print(c.c_name)
# 多對(duì)多反向查詢-根據(jù)related_name查詢 # 查詢選修了數(shù)學(xué)課程的學(xué)生姓名 course = Course.objects.filter(c_name='數(shù)學(xué)').first() students = course.course_student.all() for s in students: print(s.s_name)
8. QuerySet常用API
我們通常做查詢操作的時(shí)候驾茴,都是通過(guò)模型名字.objects的方式進(jìn)行操作。其實(shí)模型名字.objects是一個(gè)django.db.models.manager.Manager對(duì)象氢卡,而Manager這個(gè)類是一個(gè)“空殼”的類锈至,他本身是沒(méi)有任何的屬性和方法的。他的方法全部都是通過(guò)Python動(dòng)態(tài)添加的方式译秦,從QuerySet類中拷貝過(guò)來(lái)的峡捡。
所以我們?nèi)绻胍獙W(xué)習(xí)ORM模型的查找操作,必須首先要學(xué)會(huì)QuerySet上的一些API的使用筑悴。
返回新的QuerySet的方法
filter
exclude
annotate
order_by
values
-
values_list
類似于values们拙。只不過(guò)返回的QuerySet中,存儲(chǔ)的不是字典阁吝,而是元組砚婆。
all
-
select_related
在提取某個(gè)模型的數(shù)據(jù)的同時(shí),也提前將相關(guān)聯(lián)的數(shù)據(jù)提取出來(lái)突勇∽岸ⅲ可以減少數(shù)據(jù)庫(kù)查詢的次數(shù)。selected_related只能用在一對(duì)多或者一對(duì)一中甲馋,不能用在多對(duì)多或者多對(duì)一中埂奈。
article = Article.objects.get(pk=1) >> article.author # 重新執(zhí)行一次查詢語(yǔ)句 article = Article.objects.select_related("author").get(pk=2) >> article.author # 不需要重新執(zhí)行查詢語(yǔ)句了
-
prefetch_related
這個(gè)方法和select_related非常的類似,就是在訪問(wèn)多個(gè)表中的數(shù)據(jù)的時(shí)候定躏,減少查詢的次數(shù)账磺。這個(gè)方法是為了解決多對(duì)一和多對(duì)多的關(guān)系的查詢問(wèn)題。
-
defer
在一些表中痊远,可能存在很多的字段绑谣,但是一些字段的數(shù)據(jù)量可能是比較龐大的,而此時(shí)你又不需要拗引,因此這時(shí)候我們就可以使用defer來(lái)過(guò)濾掉一些字段借宵。這個(gè)字段跟values有點(diǎn)類似矾削,只不過(guò)defer返回的不是字典壤玫,而是模型。
-
only
跟defer類似哼凯,只不過(guò)defer是過(guò)濾掉指定的字段欲间,而only是只提取指定的字段。
get
create
-
get_or_create
根據(jù)某個(gè)條件進(jìn)行查找断部,如果找到了那么就返回這條數(shù)據(jù)猎贴,如果沒(méi)有查找到,那么就創(chuàng)建一個(gè)。
bulk_create
count
first & last
aggregate
exists
distinct
update
delete
切片操作
什么時(shí)候Django會(huì)將QuerySet轉(zhuǎn)換為SQL去執(zhí)行
- 迭代
- 使用步長(zhǎng)做切片操作
- 調(diào)用len函數(shù)
- 調(diào)用list函數(shù)
- 判斷
9. 多數(shù)據(jù)庫(kù)配置
(暫用不到她渴,知道可以配置多數(shù)據(jù)庫(kù)达址,要用的時(shí)候再學(xué)吧)
10. 執(zhí)行sql語(yǔ)句
Manager.raw(raw_query, params=None, translations=None)
帶參數(shù)的SQL