最好有其他web框架基礎,不推薦小白閱讀, 1.視圖函數 1.1視圖函數的返回值 django要求視圖函數必須返回一個HTTPResponse對象,render函數和 redirect 函數其實都是返回了一個特定的HTTPResponse對象 1.2 reder函數 render函數用於渲染一個模板 ...
最好有其他web框架基礎,不推薦小白閱讀,
1.視圖函數
def login(req):
print(req.method)
# 判斷請求方式 註意都是大寫的
if req.method == "GET":
# 直接返回頁面 這裡是使用請求方式來區分同一個地址的 請求的目的
return render(req, "login.html")
elif req.method == "POST":
# 如果是post請求就獲取數據
# print(req.POST) # POST 或GET 獲取到的都是一個字典QueryDict類型
# print(req.POST.get("hobby")) # 每個值都是一個數組類型 直接get得到的是最後一個值
# print(req.POST.getlist("hobby")) # 獲取所有值 以列表形式
# 獲取用戶名和密碼:
user = req.POST.get("user")
pwd = req.POST.get("pwd")
# 查詢資料庫
pool = ZS_POOL.ConnectPool()
res = pool.execute_sql("select *from person where name = %s and password = %s",[user,pwd])
print(res)
if res[0]:
return HttpResponse("login success!")
return HttpResponse("login failed!")
return HttpResponse()
1.1視圖函數的返回值
django要求視圖函數必須返回一個HTTPResponse對象,render函數和 redirect 函數其實都是返回了一個特定的HTTPResponse對象
1.2 reder函數
render函數用於渲染一個模板文件,這裡的渲染指的是將動態數據填充到頁面文件中,
該函數接收一個request請求對象,一個模板文件,一個context,
其中context用於,向模板中傳遞數據,以字典形式,模板文件中可以使用模板語言從context中取出數據
案例:
def user_list(req):
if req.method == "GET":
return render(req,"users.html",context={"users":["jack","rose"]})
1.3 redirect函數
redirect函數用於重定向頁面,返回值為HttpResonse,需要說明的是重定向的本質是讓客戶端重新發起新請求,請求另一個地址
案例:
return redirect("/userlist")
2.配置文件
2.1靜態文件配置
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/' # 靜態路由, 路徑為根路徑+/static時將返回下列路徑中的靜態文件
# 靜態文件搜索路徑 ,可以是列表
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static")
]
2.2模板路徑配置
補充:pycharm鏈接資料庫
3.ORM
3.1django鏈接資料庫配置
3.2異常處理:
django2.2 版本時鏈接資料庫報錯:
LookupError: No installed app with label 'admin'.
查詢資料後得到的辦法是:更換版本到2.1.8
雖然解決了但是,2.1.8支持到2020年結束
更換長期版本225 沒有上面的錯誤 但是出現了新的錯誤:
按照下列步驟一步一步搞定:
https://www.cnblogs.com/yangyuanhu/p/11526256.html
3.3 同步model到資料庫
在app下的models中 創建對應的模型,模型需繼承models.Model類
類中使用Field類對象表示欄位
模型準備好後,在項目下執行命令:
python3 manager.py makemigrations # 用於創建遷移記錄
python3 manager.py migrate # 用於將最新的記錄遷移至資料庫中
需要註意: migrate 在遷移時是根據makemigrations 產生的記錄文件來進行資料庫同步的
也就意味著 必須先執行makemigrations 才能執行migrate 來同步
創建的資料庫名稱以app名稱作為首碼,如下:
註意2:資料庫操作都是針對已經註冊的app,所以需要先註冊app到配置文件中
3.4針對已存在的model欄位進行CUD
添加欄位
執行makemigrations時會遇到提示信息要求為新的欄位添加預設值 ,可以在命令行直接輸入預設值
註意:上述方式添加是一次性的不會修改欄位的預設值屬性 依然是不可為空的
或者退出後,修改代碼,如下:
刪除 修改欄位
如刪除email欄位:
修改代碼後執行遷移命令(兩條)即可
3.5利用ORM 對數據進行增刪改查
簡單查詢
#關鍵字參數 會被作為 and鏈接 返回值為一個結果集合 first 是取出第一個 user = models.User.objects.filter(user=user,pwd=pwd).first() #查詢所有數據 返回結果集 可迭代 users = models.User.objects.all()
添加數據
# ORM添加數據方式1 創建並存儲到資料庫 # user = models.User.objects.create(user=user,pwd=pwd,phone=phone) # print(user) # ORM添加數據方式2 創建對象 手動調用save方法來存儲 user = models.User(user=user,pwd=pwd,phone=phone) user.save()
刪除數據
id = req.GET.get("id") # 刪除數據 返回值為執行影響的記錄數量 可用於判斷執行是否成功 需要註意的是如果有多條記錄將全部刪除 count = models.User.objects.filter(id=id).delete()
修改數據
# 從請求中取值 id = req.POST.get("id") # 找到對象後執行update來更新數據 返回更新數量 count = models.User.objects.filter(id=id).update(user=user,pwd=pwd,phone=phone) print(count)
3.6 ORM中的多表關聯設計
班級表
class CLASS(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=20)
一對多
一個班級對應多個老師
class Teacher(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=20) # 多個老師對應同一個 班級 在老師表中保存班級表的id room = models.ForeignKey(to=CLASS,to_field="id",on_delete=models.CASCADE) # 註意 在2.* 中on_delete 沒有預設值 必須手動指定 級聯操作 # 外鍵欄位 會自動添加_id作為尾碼
多對多
一個學生對應多個老師 一個老師對應多個學生
class Student(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=20) teacher = models.ManyToManyField(to=Teacher)
4路由
4.1 提取路徑中的參數
1.* 的url 函數 與2.* re_path 使用方式一致
第一個參數為正則表達式,第二個是要調用的函數名稱
re_path下的配置以及參數捕獲
先聲明:不使用複雜的url配置直接將參數放在?後面也是可以完成所有需求的
那麼使用複雜的配置從path中取值的目的是什麼呢? 偽靜態!
而偽靜態是為了SEO優化
無名分組:
從path中使用re獲取值然後當做位置參數傳給視圖函數
re_path('^book/(\d+)/$', views.book),
#視圖函數
def book(request,any_name):
pass
有名分組:
從path中使用re獲取值然後當做關鍵字參數傳給視圖函數
re_path('^book/(?P<id>\d+)/$', views.book),
#視圖函數 參數名稱必須與url配置中完全相同
def book(request,id):
pass
4.2 2.* 下的path
2.*版本下預設使用的是path,path其實就是老版本url的有名分組,捕獲的參數都會以關鍵字的形式傳給視圖函數
- 用法:
path('gets/<page>/info', views.gets),
# <> 表示分組 括弧中的page是參數名稱
轉換器
本質就是瘋轉的正則 最後在幫你做了類型轉換
path('gets/<int:page>/info', views.gets),
自定義轉換器
當你的規則比較複雜或是要轉換為特殊的類型時可以自定義轉換器,有以下要求
regex
類屬性,字元串類型to_python(self, value)
方法,value是由類屬性regex
所匹配到的字元串,返回具體的Python變數值,以供Django傳遞到對應的視圖函數中。to_url(self, value)
方法,和to_python
相反,value是一個具體的Python變數值,返回其字元串,通常用於url反向引用。
案例:
class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value # 該轉換器用於匹配4位的整數 並轉為int類型
使用:
# 註冊 register_converter(converters.FourDigitYearConverter, 'yyyy') # 使用 urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<yyyy:year>/', views.year_archive),
4.3反向解析
何為反向,正常的請求流程是先走路由,在執行視圖函數渲染模板,
當我們在模板或者視圖函數中需要獲取路由信息時就稱之為反向解析
為什麼要這樣做呢?,目的是為了方便後續修改路由配置,反向解析可以獲取請求路徑信息,而避免直接寫死路徑帶來的麻煩事
下例方法適用於1.* 中的url函數
首先需要在路由中為這個路由指定一個名稱
- 不帶分組
#路由
re_path('books', views.books,name="path1")
#視圖函數取值
print(reverse("path1"))
#模板取值
<h1>{% url "path1" %}</h1>
- 無名分組
#路由
re_path('books/(\d+)', views.books2,name="path2"),
#視圖函數取值
print(reverse("path2",args=("100",)))
#模板取值
<h1>{% url "path2" "1" %}</h1>
- 有名分組
#路由
re_path('books3/(?P<id>\d+)', views.books3,name="path3"),
#視圖函數取值
print(reverse("path3", args=("100",)))
# or
print(reverse("path3", kwargs={"id": "100"}))
#模板取值
<h1>{% url "path3" "1" %}</h1>
# or
<h1>{% url "path3" id="1" %}</h1>
另外反向解析本質就是做字元串拼接,所以無論在什麼位置只要存在就可以解析
4.4路由分發
當應用程式體積大 模塊多時需要拆分多個不同APP,同時urls也不能全都寫在主路由配置中
這就需要在主路由配置文件中引入其他app中的路由配置信息
- 引入案例:
主路由配置文件:
from django.urls import include, path
urlpatterns = [
# 可以是完整的模塊路徑
path('help/', include('apps.help.urls')),
# 可以是一個已經導入的模塊名稱
path('credit/', include(a_urls)),
]
當請求路徑為 http:xxxxxxx:8000/help/test/ 是將請求交給apps.help.urls來進行匹配,
需要強調的是在apps.help.urls中拿到的路徑是已經去除首碼的,也就是只有/test/部分
- 使用include來簡化書寫:
簡化前
urlpatterns = [
path('<page_slug>-<page_id>/history/', views.history),
path('<page_slug>-<page_id>/edit/', views.edit),
path('<page_slug>-<page_id>/discuss/', views.discuss),
path('<page_slug>-<page_id>/permissions/', views.permissions),
]
簡化後:
urlpatterns = [
path('<page_slug>-<page_id>/', include([
path('history/', views.history),
path('edit/', views.edit),
path('discuss/', views.discuss),
path('permissions/', views.permissions),
])),
]
路由分發中的名稱空間
當多個app中出現了相同名稱的路由時,反向解析將出現問題
- 解決方案1
手動給name添加別名
re_path('^books$', views.books,name="appname_path1"),
- 解決方案2
在include中指定namespace
path("app01/",include("app01.urls",namespace="app01"))
#視圖函數取值
print(reverse("app01:path1"))
#模板取值
<h1>{% url "app01:path1" %}</h1>