Django 千鋒培訓讀書筆記 https://www.bilibili.com/video/av17879644/?p=1 切換到創建項目的目錄 cd C:\Users\admin\Desktop\DjangoProject 創建名為project的項目命令 django-admin startproject project 注:所有路徑不要有中文 切換到目錄cd C:\Users\admin\Desktop\DjangoProject\project 目錄層級說明:manage.py 一個命令行工具,可以讓我們用多種方式對Django項目進行交互 __init__.py 一個空文件,它告訴Python這個目錄應該被看做一個包 settings.py 項目的配置文件(主要處理文件) urls.py 項目的url聲明 (主要處理文件) wsgi.py 項目與WSGI兼容的Web服務器入口 配置數據庫 Django默認使用SQLite數據庫 在settings.py文件中通過DATABASES選項進行數據庫配置 配置MySQL Python3.x中安裝的是PyMySQL 在__init__.py文件中寫入兩行代碼import pymysql pymysql.install_as_MySQLdb() 以數據庫sunck為例進行示范:對settings.py中的DATABASES進行設置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': "sunck", 'USER': "root", 'PASSWORD': "admin123", 'HOST': "localhost", 'PORT': "3306" } } 創建應用--在一個項目中可以創建多個應用,每個應用進行一種業務處理 打開CMD,進入project(目錄名)的目錄下,輸入命令創建名為myApp的app: python manage.py startapp myAPP myAPP目錄說明 admin.py 進行站點配置 models.py 創建模型 views.py 創建視圖 激活應用 在settings.py文件中,將myApp應用加入到INSTALLED_APPS選項中 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'myApp', ] 定義模型 概述:有一個數據表就對應有一個模型 在models.py文件中定義模型 引入:from django.db import models 模型類要繼承models.Model類 示例: class Grades(models.Model): gname = models.CharField(max_length=20) gdate = models.DateTimeField() ggirlnum = models.IntegerField() gboynum = models.IntegerField() isDelete = models.BooleanField(default=False) class Students(models.Model): sname = models.CharField(max_length=20) sgender = models.BooleanField(default=True) sage = models.IntegerField() scontend = models.CharField(max_length=20) isDelete = models.BooleanField(default=False) sgrade = models.ForeignKey("Grades", on_delete=models.CASCADE,) 說明: 不需要定義主鍵,在生成時自動添加,並且值為自動增加 在數據庫中生成數據表 生成遷移文件 執行 python manage.py makemigrations 在migrations目錄下生成一個遷移文件,此時數據庫中還沒有生成數據表 執行遷移 執行 python manage.py migrate 相當於執行MySQL語句創建了數據表 測試數據操作 進入到python shell 執行 python manage.py shell 引入包 from myApp.models import Grades, Students from django.utils import timezone from datetime import * 查詢所有數據 類名.objects.all() 示例: Grades.objects.all() 添加數據 本質:創建一個模型類的對象實例 示例:CMD窗口下: grade1 = Grades() grade1.gname = "python04" grade1.gdate = datetime(year=2017, month=7, day=17) grade1.ggirlnum = 3 grade1.gboynum = 70 grade1.save() 查看某個對象 類名.objects(pk=索引號) 示例: Grades.objects.get(pk=2) Grades.objects.all() 修改某個數據 模型對象屬性 = 新值 示例: grade2.gboynum = 60 grade2.save() 刪除數據 模型對象.delete() grade2.delete() 注意:這是物理刪除,數據庫中的相應數據被永久刪除 關聯對象 示例: stu = Students() stu.sname = "Xue Yanmei" stu.sgender = False stu.sage = 20 stu.scontend = "I am Xue Yanmei" stu.sgrade = grade1 stu.save() 獲得關聯對象的集合 需求:獵取python04班級的所有學生 對象名.關聯的類名小寫_set.all() 示例:grade1.students_set.all() 需求:創建曾志偉,屬於python04班級 示例: stu3 = grade1.students_set.create(sname=u'Zhen Zhiwei',sgender=True,scontend=u"I am Zhen Zhiwei",sage=45) 注意:這樣創建的數據直接被添加到了數據庫當中。 啟動服務器: 格式:python manage.py runserver ip:port 注意:ip可以不寫,不寫代表本機ip 端口號默認是8000 python manage.py runserver 說明: 這是一個純python編寫的輕量級web服務器,僅僅在開發測試中使用這個 Admin站點管理: 概述: 內容發布:負責添加,修改,刪除內容的 公告訪問 配置Admin應用: 在settings.py文件中的INSTALLED_APPS中添加'django.contrib.admin', 這條默認是添加好的。 創建管理員用戶: 在項目目錄下執行 python manage.py createsuperuser 依次輸入賬號名,郵箱,密碼即可完成用戶創建 登陸: http://127.0.0.1:8000/admin/ 漢化: 把project\settings.py 中作如下設定:LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai' 管理數據表: 修改 myAPP\admin.py 如下: from django.contrib import admin # Register your models here. from .models import Grades, Students # 注冊 admin.site.register(Grades) admin.site.register(Students) 自定義管理頁面: 屬性說明 # 列表頁屬性 list_display = [] # 顯示字段設置 list_filter = [] # 過濾字段設置 search_fields = [] # 搜索字段設置 list_per_page = [] # 分頁設置 # 添加,修改頁屬性 fields = [] # 規定屬性的先后順序 fieldsets = [] # 給屬性分組 注意:fields與fieldsets不能同時使用 屬性示例: # 列表頁屬性 list_display = ['pk', 'gname', 'gdate', 'ggirlnum', 'gboynum', 'isDelete'] list_filter = ['gname'] search_fields = ['gname'] list_per_page = 5 # 添加,修改頁屬性 # fields = ['ggirlnum', 'gboynum', 'gname', 'gdate', 'isDelete'] fieldsets = [ ("num",{"fields":['ggirlnum', 'gboynum']}), ("base", {"fields":["gname", "gdate", "isDelete"]}), ] 關聯對象:需求:在創建一個班級時可以直接添加幾個學生 class StudentsInfo(admin.TabularInline):# 可選參數admin.StackedInline model = Students extra = 2 class GradesAdmin(admin.ModelAdmin): inlines = [StudentsInfo] 布爾值顯示問題示例: class StudentsAdmin(admin.ModelAdmin): def gender(self): if self.sgender: return "男" else: return "女" # 設置頁面列的名稱 gender.short_description = "性別" list_display = ['pk', 'sname', 'sage', gender, 'scontend', 'sgrade', 'isDelete'] list_per_page = 10 admin.site.register(Students, StudentsAdmin) 執行按鈕位置: class StudentsAdmin(admin.ModelAdmin): ...snip... actions_on_top = False actions_on_bottom = True admin.site.register(Students, StudentsAdmin) 使用裝飾器完成注冊: @admin.register(Students) class StudentsAdmin(admin.ModelAdmin): def gender(self): ...snip... actions_on_top = False actions_on_bottom = True 視圖的基本使用 概述: 在Django中,視圖是對web請求進行回應 視圖就是一個python函數,在views.py文件中定義。 定義視圖: 示例:在myApp\views.py中寫入 from django.shortcuts import render # Create your views here. from django.http import HttpResponse def index(request): return HttpResponse("Sunck is a good man") 配置url:方法一:path方法: 修改project目錄下的urls.py文件: from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('myApp.urls')), ] 在myApp應用目錄下創建urls.py文件: from django.urls import path, include from . import views urlpatterns = [ path('',views.index), ] 配置url:方法二:url方法: 修改project目錄下的urls.py文件: from django.contrib import admin from django.conf.urls import url,include urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('myApp.urls')), ] 在myApp應用目錄下創建urls.py文件: from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index), ] 模板的基本使用: 概述:模板是HTML頁面,可以根據視圖中傳遞過來的數據進行填充 創建模板: 創建templates目錄,在目錄下創建對應項目的模板目錄(project/templates/myApp) 配置模板路徑: 修改settings.py文件下的TEMPLATES下的'DIRS'為'DIRS': [os.path.join(BASE_DIR, 'templates')], 定義grades.html與students.html模板: 在templates\myApp\目錄下創建grades.html與students.html模板文件 模板語法: {{輸出值,可以是變量,也可以是對象,屬性}} {%執行代碼段%} http://127.0.0.1:8000/grades 寫grades.html模板: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>班級信息</title> </head> <body> <h1>班級信息列表</h1> <ul> <!--[python04, python05, python06]--> {%for grade in grades%} <li> <a href="#">{{grade.gname}}</a> </li> {%endfor%} </ul> </body> </html> 定義視圖:myApp\views.py from .models import Grades def grades(request): # 去模板里取數據 gradesList = Grades.objects.all() # 將數據傳遞給模板,模板再渲染頁面,將渲染好的頁面返回給瀏覽器 return render(request, 'myApp/grades.html', {"grades": gradesList}) 配置url:myApp\urls.py urlpatterns = [ url(r'^$', views.index), url(r'^(\d+)/(\d+)$', views.detail), url(r'^grades/', views.grades) ] http://127.0.0.1:8000/students 寫students.html模板 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>學生頁面</title> </head> <body> <h1>學生信息列表</h1> <ul> {%for student in students%} <li> {{student.sname}}--{{student.scontend}} </li> {%endfor%} </ul> </body> </html> 定義視圖:myApp\views.py from .models import Students def students(request): studentsList = Students.objects.all() return render(request, 'myApp/students.html', {"students": studentsList}) 配置url:myApp\urls.py urlpatterns = [ url(r'^$', views.index), url(r'^(\d+)/(\d+)$', views.detail), url(r'^grades/', views.grades), url(r'^students/', views.students), ] 需求:點擊班級,顯示對應班級的學生名字 運行不正常https://www.bilibili.com/video/av17879644/?p=12 Django流程梳理 創建工程:執行 django-admin startproject 工程名 創建項目:執行 python manage.py startapp 項目名稱 激活項目:修改 settings.py中的INSTALLED_APPS 配置數據庫: 修改__init__.py文件 修改settings.py文件中的DATABASES 創建模型類:在項目目錄下的models.py文件中創建 生成遷移文件:執行python manage.py makemigrations 執行遷移:執行python manage.py migrate 配置站點:略 創建模板目錄/項目模板目錄 在settings.py中的TEMPLATES添加templates路徑 在工程目錄下(project)修改urls.py 在項目目錄下創建urls.py 使用他人Django代碼需要的簡易修改: 1.在settings.py中修改數據庫名 2.在settings.py中修改數據庫密碼 3.刪除由內向外文件(在對應目錄里鼠標右鍵刪除) 4.在數據庫中創建對應第一步的數據庫(自己在SQL中創建) 5.執行生成遷移文件 6.執行遷移 7.啟動服務 8.瀏覽器測試 Django模型 Django對各種數據庫提供了很好的支持,Django為這些數據庫提供了統一的調用API 我們可以根據不同的業務需求選擇不同的數據庫。 配置數據庫 修改工程目錄下的__init__.py文件 import pymysql pymysql.install_ad_MySQLdb() 修改settings.py文件中的DATABASES 開發流程 配置數據庫 定義模型類:一個模型都在數據庫中對應一張數據庫表 生成遷移文件 執行遷移生成數據表 使用模型類進行增刪改查 ORM 概述:對象-關系-映射 任務: 根據對象的類型生成表結構 將對象,列表的操作轉換成SQL語句 將SQL語句查詢到的結果轉換為對象,列表 優點: 極大的減輕了開發人員的工作量,不需要面對因數據庫的變更而修改代碼的問題 定義模型 模型,屬性,表,字段之間的關系 一個模型類在數據庫中對應一張表,在模型類中定義的屬性,對應該模型對照表中的一個字段 定義屬性:見下文 創建模型類 元選項 在模型類中定義Meta類,用於設置元信息 示例: class Meta: db_table = "students" ordering = ['id'] db_table 定義數據表名,推薦用小寫字母,數據表名默認為項目名小寫_類名小寫 ordering 對象的默認排序字段,獲取對象的列表時使用 示例: ordering['id'] id按升序排列 ordering['-id'] id按降序排列 注意:排序會增加數據庫開銷 模型成員 類屬性 隱藏類屬性objects: 是Manager類型的一個對象,作用是與數據庫進行交互 當定義模型類時沒有指定管理器,則Django為模型創建一個名為objects的管理器 自定義管理器示例: 定義stuObj管理器: stuObj = models.Manager() 當為模型指定模型管理器,Django就不再為模型類生成objects模型管理器了。 自定義管理器Manager類 模型管理器是Django的模型進行與數據庫交互的窗口,一個模型可以有多個模型管理器 作用: 向管理器類中添加額外的方法 修改管理器返回的原始查詢集 通常會重寫get_queryset()方法 代碼示例: class StudentsManager(models.Manager): def get_queryset(self): return super(StudentsManger, self).get_queryset().filter(isDelete=False) class Students(model.Moder): # 自定義模型管理器 # 當自定義模型管理器,objects就不存在了 stuObj = models.Manger() stuObj2 = StudentsManager() 創建對象 目的:向數據庫中添加數據 當創建對象時,django不會對數據庫進行讀寫操作,當調用save()方法時才與數據庫交互,將對象保存在數據庫表中。 注意: __init__方法已經在父類models.Model中使用,在自定義的模型中無法使用。 方法: 在模型類中增加一個類方法,示例如下: class Students(model.Moder): ...snip... @classmethod def createStudent(cls, name, age, gender, contend, grade,lastT, createT, isD=False): stu = cls(sname=name, sage=age, sgender=gender, scontend=contend, sgrade=grade, lastTime=lastT, createTime=createT, isDelete=isD) return stu 在自定義管理器中添加一個方法,示例如下: class StudentsManager(models.Manager): def get_queryset(self): return super(StudentsManager, self).get_queryset().filter(isDelete=False) def createStudent(self, name, age, gender, contend, grade, lastT, createT, isD=False): stu = self.model() # print(type(grade)) stu.sname = name stu.sage = age stu.sgender = gender stu.scontend = contend stu.sgrade = grade stu.lastTime = lastT stu.createTime = createT return stu 模型查詢 概述 查詢集表示從數據庫獲取的對象的集合 查詢集可以有多個過濾器 過濾器就是一個函數,基於所給的參數限制查詢集結果 從SQL角度來說,查詢集和select語句等價,過濾器就像where條件 查詢集 在管理器上調用過濾器方法返回查詢集 查詢集經過過濾器篩選后返回新的查詢集,所以可以寫成鏈式調用 惰性執行 創建查詢集不會帶來任何數據庫的訪問,直到調用數據庫時,才會訪問數據 直接訪問數據的情況: 迭代 序列化 與if合用 返回查詢集的方法稱為過濾器 all():返回查詢集中的所有數據 filter():保留符合條件的數據 filter(鍵=值) filter(鍵=值,鍵=值) filter(鍵=值).filter(鍵=值) 且的關系 exclude():過濾掉符合條件的 order_by():排序 values():一條數據就是一個字典,返回一個列表 get() 返回一個滿足條件的對象 注意: 如果沒有找到符合條件的對象,會引發模型類.DoesNotExist異常 如果找到多個對象,會引發模型類MultipleObjectsReturned異常 count():返回查詢集中對象的個數 first():返回查詢集中第一個對象 last():返回查詢集中最后一個對象 exits():判斷查詢集中是否有數據,如果有數據返回 True,否則返回 False. 限制查詢集 查詢集返回列表,可以使用下標的方法進行限制,等同於sql中的limit語句 注意:下標不能是負數 示例:studentsList = Students.stuObj2.all()[0:5] 查詢集的緩存 概述: 每個查詢集都包含一個緩存,來最小化對數據庫的訪問 在新建的查詢集中,緩存首次為空,第一次對查詢集求值,會發生數據緩存,Django會將查詢出來的數據做一個緩存,並返回查詢結果。 以后的查詢直接使用查詢集的緩存 字段查詢 概述 實現了sql中的where語句,作為方法filter(),exclude(),get()的參數 語法:屬性名稱__比較運算符=值 外鍵:屬性名稱_id 轉義:類似sql中的like語句 like有關情況看我哥他%是為了匹配點位,匹配數據中的%使用(where like "\%") filter(sname__contains="%") 比較運算符 exact:判斷,大小寫敏感 filter(isDelete=False) contains:是否包含,大小寫敏感 studentsList = Students.stuObj2.filter(sname__contains="孫") startswith,endswith:以value開頭或結尾,大小寫敏感 以上四個在前面加上i,就表示不區分大小寫iexact,icontains,istartswith,iendswith isnull,isnotnull 是否為空 filter(sname__isnull=False) in:是否包含在范圍內 gt大於,gte大於等於,lt小於,lte小於等於 year,month,day,week_day,hour,minute,second studentsList = Students.stuObj2.filter(lastTime__year=2017) 跨關聯查詢 處理join查詢 語法: 模型類名__屬性名__比較運算符 # 描述中帶有‘薛延美’這三個字的數據是屬於哪個班級的 grade = Grades.objects.filter(students__scontend__contains='薛延美') print(grade) 查詢快捷pk代表的主鍵 聚合函數 使用aggregate函數返回聚合函數的值 Avg Count Max maxAge = Student.stuObj2.aggregate(Max('sage')) maxAge為最大的sage。 Min Sum F對象 可以使用模型的A屬性與B屬性進行比較 from django.db.models import F,Q def grades1(request): g = Grades.objects.filter(ggirlnum__gt=F('gboynum')) print(g) # [<Grades: python02>,<Grades: python03>] return HttpResponse("OOOOOOOo") 支持F對象的算術運算 g = Grades.objects.filter(ggirlnum__gt=F('gboynum')+20) Q對象 概述:過濾器的方法的關鍵字參數,條件為And模式 需求:進行or查詢 解決:使用Q對象 def students4(request): studentsList = Students.stuObj2.filter(Q(pk__lte=3) | Q(sage__gt=50)) return render(request, 'myApp/students.html', {"students": studentsList}) 只有一個Q對象的時候,就是用於正常匹配條件 studentsList = Students.stuObj2.filter(~Q(pk__lte=3)) ~Q是取反 定義屬性 概述: django根據屬性的類型確定以下信息 當前選擇的數據庫支持字段的類型 渲染管理表單時使用的默認html控件 在管理站點最低限度的驗證 django會為表增加自動增長的主鍵列,每個模型只能有一個主鍵列,如 果使用選項設置某屬性為主鍵列后,則django不會再生成默認的主鍵列 屬性命名限制 遵循標識符規則,且變量不能與Python保留字相同 由於django的查詢方式,不允許使用連續的下划線 庫 定義屬性時,需要字段類型,字段類型被定義在django.db.models.fields目錄下, 為了方便使用,被導入到django.db.models中 使用方式 導入: from django.db import models 通過 models.Field創建字段類型的對象,賦值給屬性 邏輯刪除 對於重要類型都做邏輯刪除,不做物理刪除,實現方法是定義idDelete屬性, 類型為BooleanField,默認值為False 字段類型 autoField 一個根據實際ID自動增長的IntegerField,通常不指定, 如果不指定,一個主鍵字段將自動添加到模型中 CharField(max_length=字符長度) 字符串,默認的表彰樣式是TextInput TextField 大文本字段,一般超過4000時使用,默認的表單控件是Textarea IntegerField 整數 DecimalField(max_digits=None, decimal_places=None) 使用Python的Decimal實例表示的十進制浮點數 參數說明 DecimalField.max_digits 位數總數 DecimalField.decimal_places 小數點后的數字位置 FloatField 使用Python的float實例來表示的浮點數 BooleanField True/False 字段,此字段的默認表彰控制是CheckboxInput NullBooleanField 支持 Null, True, False 三種值 DateField([auto_now=False, auto_now_add=False]) 使用Python的datetime.date實例表示的日期 參數說明: DateField.auto_now 每次保存對象時,自動設置該字段為當前時間,用於“最后一次修改” 的時間戳,它總是使用當前日期,默認為 False DateField.auto_now_add 當前對象第一次被創建時自動設置當前時間,用於創建的時間戳, 它總是使用當前日期,默認為 False 說明 該字段默認對應的表單控件是一個TextInput.在管理員站點添加了一個 JavaScript寫的日歷控件,和一個“Today”的快捷按鈕,包含了一個額外 的invalid_date錯誤消息鍵 注意 auto_now_add, auto_now, and default 這些設置是相互排斥的,他們之間 的任何組合將會發生錯誤的結果 TimeField 使用Python的datetime.time實例表示的時間,參數同DateField DateTimeField 使用Python的datetime datetime實例表示的日期和時間,參數同DateField FileField 一個上傳文件的字段 ImageField 繼承了FileField的所有屬性和方法,但對上傳的對象進行校驗, 確保它是一個有效的image 字段選項 概述 通過字段選項,可以實現對字段的約束 在字段對象中通過關鍵字參數指定 null 如果為True,Django將空值以NULL存儲在數據庫中,默認值為 False blanke 如果為True,則該字段允許為空白,默認值為 False 注意 null是數據庫范疇的概念,blank是表彰驗證范疇的概念 db_column 字段的名稱,如果未指定,則使用屬性的名稱 db_index 若值為 True,則在表中會為此字段創建索引 default 默認值 primary_key 若為 True,則該字段會成為模型的主鍵字段 unique 如果為 True,這個字段在表中必須有唯一值 關系 分類 ForeignKey:一對多,將字段定義在多的端中 ManyToManyField:多對多,將字段定義在兩端中 OneToOneField:一對一,將字段定義在任意一端中 用一訪問多 格式 對象.模型類小寫_set 示例 grade.students_set 用一訪問一 格式 對象.模型類小寫 示例 grade.studnets 訪問id 格式 對象.屬性_id 示例 student.sgrade_id 視圖 概述: 作用:視圖接收web請求,並響應web請求 本質:視圖就是python中的一個函數 響應: 響應過程: 用戶在瀏覽器中輸入網址www.sunck.wang/sunck/index.html ---網址---> django獲取網址信息,去掉IP與端口號,網址變成:sunck/index.html ---虛擬路徑與文件名---> url管理器逐個匹配urlconf,記錄視圖函數 ---視圖函數名---> 視圖管理,找到對應的視圖去執行,返回結果給瀏覽器 ---響應的數據---> 返回第一步:用戶在瀏覽器中輸入網址 網頁 重定向 錯誤視圖 404視圖:找不到網頁(url匹配不成功時返回)時返回 在templates目錄下定義404.html <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>頁面丟失</h1> <h2>{{request_path}}</h2> </body> </html> request_path:導致錯誤的網址 配置settings.py DEBUG 如果為 True,永遠不會調用404頁面,需要調整為 False 才會顯示 ALLOWED_HOSTS = ['*'] 500視圖:在視圖代碼中出現錯誤(服務器代碼錯誤) 400視圖:錯誤出現在客戶的操作 JSON數據 url配置 配置流程: 制定根級url配置文件 settings.py文件中的ROOT_URLCONF ROOT_URLCONF = 'project.urls' 默認實現了 urlpatterns 一個url實例的列表 url對象 正則表達式 視圖名稱 名稱 url匹配正則的注意事項 如果想要從url中獲取一個值,需要對正則加小括號 匹配正則前方不需要加'/' 正則前需要加'r'表示字符串不轉義 引入其他url配置 在應用中創建urls.py文件,定義本應用的url配置,在工程urls.py中使用include方法 project\urls.py from django.contrib import admin from django.conf.urls import url,include urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('myApp.urls', namespace="myAPP")), ] myApp\urls.py from django.urls import path, include from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index, name="index"), ] url的反向解析 概述:如果在視圖,模板中使用了硬編碼鏈接,在url配置發生改變時,動態生成鏈接的地址 解決:在使用鏈接時,通過url配置的名稱,動態生成url地址 作用:使用url模板 視圖函數 定義視圖: 本質:一個函數 視圖參數: 一個HttpRequest的實例 通過正則表達式獲取的參數 位置:一般在views.py文件下定義 HttpRequest對象 概述: 服務器接收http請求后,會根據報文創建HttpRequest對象 視圖的第一個參數就是HttpRequest對象 django創建的,之后調用視圖時傳遞給視圖 屬性 path:請求的完整路徑(不包括域名和端口) method:表示請求的方式,常用的有GET,POST encoding:表示瀏覽器提交的數據的編碼方式,一般為utf-8 GET:類似於字典的對象,包含了get請求的所有參數 POST:類似於字典的對象,包含了post請求的所有參數 FILES:類似字典的對象,包含了所有上傳的文件 COOKIES:字典,包含所有的cookie session:類似字典的對象,表示當前會話 方法 is_ajax():如果是通過XMLHttpRequest發起的,返回 True QueryDict對象 request對象中的GET,POST都屬於QueryDict對象 方法: get(): 根據鍵獲取值,只能獲取一個值 www.sunck.wang/abc?a=1&b=2&c=3 getlist() 將鍵的值以列表的形式返回 可以獲取多個值 www.sunck.wang/abc?a=1&b=2&c=3 GET屬性 獲取瀏覽器傳遞過來數據 www.sunck.wang/abc?a=1&b=2&c=3 urls.py url(r'^get1', views.get1), #結尾不能加$,否則無法匹配 views.py def get1(request): a = request.GET.get('a') b = request.GET.get('b') c = request.GET.get('c') return HttpResponse(a + " " + b + " " + c) www.sunck.wang/abc?a=1&a=2&c=3 urls.py url(r'^get2', views.get2), views.py def get2(request): a = request.GET.getlist('a') a1 = a[0] a2 = a[1] c = request.GET.get('c') return HttpResponse(a1 + " " + a2 + " " + c) POST屬性 使用表單模擬POST請求 關閉CSRF:project\project\settings.py 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', ] 示例: def showregist(request): return render(request, 'myApp/regist.html',) def regist(request): name = request.POST.get("name") gender = request.POST.get("gender") age = request.POST.get("age") hobby = request.POST.getlist("hobby") print(name) print(gender) print(age) print(hobby) return HttpResponse("regist") 路徑: url(r'^showregist/$', views.showregist), url(r'^showregist/regist/$', views.regist), 頁面: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>注冊</title> </head> <body> <form action="regist/" method="post"> 姓名:<input type="text" name="name" value=""/> <hr> 性別:<input type="radio" name="gender" value="1">男<input type="radio" name="gender" value="0">女 <hr> 愛好:<input type="checkbox" name="hobby" value="power"/>權利<input type="checkbox" name="hobby" value="money">金錢<input type="checkbox" name="hobby" value="beauty">美女<input type="checkbox" name="hobby" value="Tesla">Tesla <hr> <input type="submit" value="注冊"> </form> </body> </html> HttpResponse對象 概述: 作用:給瀏覽器返回數據 HttpRequest對象是由Django創建的,HttpResponse對象是由程序員創建 用法: 不用模板,直接返回數據 語句示例:return HttpResponse("Sunck is a good man") 調用模板 使用render方法 原型:render(request, templateName[, context]) 作用:結合數據和模板,返回一個完整的HTML頁面 參數: request:請求體對象 templateName:模板路徑 context:傳遞給需要渲染在模板上的數據 屬性 content:表示返回內容 charset:編碼格式 status_code:響應狀態碼 200 304 404 400 content-type:指定輸出的MIME類型 方法 init:使用頁面內容實例化HttpResponse對象 write(content):以文件的形式寫入 flush():以文件的形式輸出緩沖區 set_cookie(key, value, maxAge=None, exprise=None) delete_cookie(key): 刪除cookie 如果刪除一個不存在的cookie,就當什么都沒發生 子類HttpResponseRedirect 功能:重定向,服務器端的跳轉 簡寫 redirect(to) to推薦使用反向解析 示例: from django.http import HttpResponseRedirect from django.shortcuts import redirect def redirect1(request): # return HttpResponseRedirect('/redirect2') return redirect('/redirect2') def redirect2(request): return HttpResponse("我是重定向后的視圖") 子類JsonResponse 返回Json數據,一般用於異步請求 __init__(self.data) data 字典 注意:Content-type類型為application/json 狀態保持 http協議是無狀態的,每次請求都是一次新的請求,它不記得之前的請求。 客戶端與服務器的一次通信就是一次會話 實現狀態的保持,在客戶端或服務端存儲有關會話的數據 存儲的方式 cookie:所有數據存儲在客戶端,不要存儲敏感的數據 session:所有的數據存儲在服務端,在客戶端用cookie存儲session_id 狀態保持的目的: 在一段時間內跟蹤請求者的狀態,可以實現跨頁面訪問當前的請求者的數據 注意:不同的請求者之間不會共享這個數據,與請求者一一對應 啟用session:project\project\settings.py INSTALLED_APPS 'django.contrib.sessions', MIDDLEWARE 'django.contrib.sessions.middleware.SessionMiddleware', 使用session 啟用session后,每個httpRequest對象都有一個session屬性 get[key, default=None] 根據鍵獲取session值 clear() 清空所有會話 flush() 刪除當前會話並刪除會話的cookie 示例: # session def main(request): # 取session username = request.session.get('name', '游客') print(username) return render(request, 'myApp/main.html', {'username': username}) def login(request): return render(request, 'myApp/login.html') def showmain(request): print("*****************") username = request.POST.get('username') # 存儲session request.session['name'] = username return redirect('/main/') from django.contrib.auth import logout def quit(request): # 清除session logout(request) # 方法1,推薦 # request.session.clear() # 方法2 request.session.flush() # 方法3 return redirect('/main/') 設置session過期時間 set_expiry(value) request.session.set_expiry(10) 設置為10秒后過期 如果不設置,2個星期后過期 value設置為0代表關閉瀏覽器時過期 value設置為None代表設置永不過期,不推薦 Redis使用:略 ************************************************************************************************************ ****************************************第二篇筆記從這里開始************************************************ ************************************************************************************************************ 模板 定義模板 變量 變量傳遞給模板的數據 要遵守標識符規則 語法 {{ var }} 注意:如果使用的變量不存在,則插入的是空字符串 在模板中使用點語法 字典查詢 屬性或者方法 數字索引 在模板中調用對象的方法 注意:在模板里定義的函數不能傳遞self以外的參數 標簽:語法 {% tag %} 作用 在輸出中創建文本 控制邏輯和循環 標簽示例: if 格式 {% if 表達式 %} 語句 {% endif %} if-else 格式 {% if 表達式 %} 語句1 {% else %} 語句else {% endif %} if-elif-else 格式 {% if 表達式 %} 語句1 {% elif 表達式 %} 語句2 ... {% else %} 語句else {% endif %} for 格式 {% for 變量 in 列表 %} 語句 {% endfor %} 格式2 {% for 變量 in 列表 %} 語句 {% empty %} # 注意:列表為空或者列表不存在時執行語句2 語句2 {% endfor %} 格式3 {{ forloop.counter }} 示例: <ul> {% for stu in students %} <li> {{forloop.counter}}--{{stu.sname}}--{{stu.sgrade}} </li> {% empty %} <li>目前沒有學生</li> {% endfor %} commnet 格式 {% commnet %} 被注釋的內容 {% endcomment %} 作用:相當於多行注釋,被注釋的內容不再執行 ifequal/ifnotequal 作用 判斷是否相等或者不相等 格式 {% ifequal 值1 值2 %} 語句1 {% endifequal %} # 如果值1等於值2,執行語句1,否則不執行語句1 include 作用:加載模板並以標簽內的參數渲染 格式:{% include '模板目錄' 參數1 參數2 %} url 作用:反射解析 格式:{% url 'namespace: name' p1 p2 %} csrf_token 作用:用於跨站請求偽造保護 格式:{% csrf_token %} block, extends 作用:用於模板的繼承 autoescape 作用:用於HTML轉義 過濾器 語法 {{ var|過濾器 }} 作用:在變量被顯示前修改它,只是加一個效果,對變量不會造成影響 示例: lower upper 過濾器可以傳遞參數,參數用引號引起來 join 格式 列表|join:"#" 示例:{{list1|join:"#"}} 如果一個變量沒有被提供,或者值為false,空,我們可以通過 default 語法使用默認值 格式: {{str1|default:"沒有"}} 根據給定格式轉換日期為字符串:date 格式: {{dateVal|date:'y-m-d'}} HTML轉義:escape 加減乘除示例: <h1>num = {{num|add:10}}</h1> <h1>num = {{num|add:-10}}</h1> <h1>num = {% num widthratio num 1 5%}</h1> <h1>num = {% num widthratio num 5 1%}</h1> 注釋 單行注釋:語法: {# 被注釋的內容 #} 多行注釋 {% commnet %} 被注釋的內容 {% endcomment %} 反射解析 示例: project/project/urls.py url(r'^', include('myApp.urls', namespace='app')), project/myApp/urls.py url(r'^good/(\d+)$', views.good, name="good") templates/good.html <a href={% url 'app:good' 1 %}>鏈接</a> 模板繼承 作用:模板繼承可以減少頁面的重復定義,實現頁面的重用 block標簽:在父模板中預留區域 ,子模板去填充 語法 : {% block 標簽名 %} {% endblock 標簽名 %} extends標簽:繼承模板,需要寫在模板文件的第一行 語法 : {% extends 'myApp/base.html' %} {% block main %} 內容 {% endblock 標簽名 %} 示例: 定義父模板 body標簽中 {% block main %} {% endblock main %} {% block main %} {% endblock main2 %} 定義子模板 {% extends 'myApp/base.html' %} {% block main %} <h1>sunck is a good man</h1> {% endblock main %} {% block main2 %} <h1>kaige is a good man</h1> {% endblock main2 %} HTML轉義 問題:return render(request, 'myApp/index.html', {"code": "<h1>sunck is a very good man</h1>"})中的{{code}} {{code}}里的code被當作<h1>sunck is a very good man</h1>顯示,未經過渲染 解決方法: {{code|safe}} 或 {% autoescape off %} {{code}} {% endautoescape %} # 這個可以一口氣解決一堆 CSRF: 跨站請求偽造 某些惡意網站包含鏈接,表單,按鈕,js,利用登錄用戶在瀏覽器中認證,從而攻擊服務 防止CSRF 在settings.py文件的MIDDLEWARE增加'django.middleware.csrf.CsrfViewMiddleware' {% csrf_token %} 驗證碼 作用 在用戶注冊,登錄頁面的時候使用,為了防止暴力請求,減輕服務器的壓力 是防止CSRF的一種方式 驗證碼代碼示例: 寫在views.py里面 ================================================================================================= def verifycode(request): # 引入繪圖模塊 from PIL import Image, ImageDraw, ImageFont # 引入隨機函數模塊 import random # 定義變量,用於畫面的背景色,寬,高 bgcolor = (random.randrange(20, 100), random.randrange(20, 100), random.randrange(20, 100)) width = 100 height = 50 # 創建畫面對象 im = Image.new('RGB', (width, height), bgcolor) # 創建畫面對象 draw = ImageDraw.Draw(im) # 調用畫筆的point()函數繪制噪點 for i in range(0, 100): xy = (random.randrange(0, width), random.randrange(0, height)) fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) draw.point(xy, fill=fill) # 定義驗證碼的備選值 str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm' # 隨機選取4個值作為驗證碼 rand_str = '' for i in range(0, 4): rand_str += str[random.randrange(0, len(str))] # 構造字體對象 font = ImageFont.truetype(r'C:\Windows\Fonts\AdobeArabic-Bold.otf', 40) # 構造字體顏色 fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255)) fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255)) fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255)) fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255)) # 繪制4個字 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1) draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2) draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3) draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4) # 釋放畫筆 del draw # 存入session,用於做進一步的驗證 request.session['verifycode'] = rand_str # 內存文件操作 import io buf = io.BytesIO() # 將圖片保存在內存中,文件類型為png im.save(buf, 'png') # 將內存中的圖片數據返回給客戶端,MIME類型為圖片png return HttpResponse(buf.getvalue(), 'image/png') from django.shortcuts import render, redirect def verifycodefile(request): f = request.session["falg"] str = "" if f == False: str = "請重新輸入!" request.session.clear() return render(request, 'myApp/verifycodefile.html', {"flag":str}) def verifycodecheck(request): code1 = request.POST.get("verifycode").upper() code2 = request.session["verify"].upper() if code1 == code2: return render(request, 'myApp/success.html') else: request.session["flag"] = False return redirect('/verifycodefile') ============================================================================== 寫在verifycodefile.html的<body>標簽中 <body> <form method="post" action="/verifycodecheck/"> {%csrf_token%} <input type="text" name="verifycode"/> <img src="/verifycode"> <input type="submit" name="登錄"> <span>{{flag}}</span> </form> </body> ============================================================================== Django高級擴展 靜態文件 css,js,圖片,json文件,字體文件等 配置settings.py STATIC_URL = '/static' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] 中間件 概述:一個輕量級,底層的插件,可以介入Django的請求和響應。 本質:一個Python類 方法: __init__ 不需要傳參數,服務器響應第一個請求的時候自動調用,用於確定是否啟用該中間件 process_request(self, request) 在執行視圖之前被調用(分配url匹配視圖之前),每個請求都會調用,返回None或者HttpResponse對象 process_view(self, request, view_func. view_args, view_kwargs) 調用視圖之前執行,每個請求都會調用,返回None或者HttpResponse對象 process_template_response(self, request, response) 在視圖剛好執行完后調用,每個請求都會調用,返回None或者HttpResponse對象 使用render process_response(self, request, response) 所有響應返回瀏覽器之前調用,每個請求都會調用,返回HttpResponse對象 process_exception(self, request, exception) 當視圖拋出異常時調用,返回HttpResponse對象 執行過程: __init__ --> process_request--> url --> process_view --> view --> process_template_response --> template --> process_response -->返回開頭部分 執行位置: 自定義中間件 在工程目錄下的middleware目錄下創建myApp 創建一個python文件 from django.utils.deprecation import middlewareMixin class MyMiddle(middlewareMixin): def process_request(self, request): print("get參數為: ", request.GET.get("a")) 使用自定義中間件 配置settings.py文件 在MIDDLEWARE中添加 'middleware.myApp.MyMiddle.MyMiddle', 上傳圖片 概述: 文件上傳時,文件數據request.FILES屬性中. 注意:form表單要上傳文件需要加enctype="multipart/form-data" 注意:上傳文件必須用post請求 存儲路徑: 在static目錄下創建upfile目錄用於存儲上傳的文件 配置settings.py文件 MDEIA_ROOT = os.path.join(BASE_DIR, r'static\upfile') views.py內容 ============================================================================== def upfile(request): return render(request, 'myApp/upfile.html') import os from django.conf import settings def savefile(request): if request.method == "POST": f = request.FILES["file"] # 文件在服務器端的路徑 filePath = os.pasth.join(settings.MDEIA_ROOT, f.name) with open(filePath, 'wb') as fp: for info in f.chunks(): fp.write(info) return HttpResponse("上傳成功。") else: return HttpResponse("上傳失敗。") ============================================================================== upfile.html中<body>里的內容 <body> <form method="post" action="/savefile" enctype="multipart/form-data"> {%csrf_token%} <input type="file" name="file"/> <input type="submit" value="上傳"/> </form> </body> ============================================================================== 分頁 Paginator對象 創建對象 格式 Paginator(列表,整數) 返回值 返回的分頁對象 屬性 count 對象總數 num_pages 頁面總數 page_range 頁碼列表 [1,2,3,4,5] 頁碼從1開始 方法 page(num) 獲得一個Page對象,如果提供的頁碼不存在會拋出"InvalidPage"異常 異常 InvalidPage:當向 page()傳遞的是一個無效的頁碼時拋出 PageNotAnInteger:當向 page()傳遞的不是一個整數時拋出 EmptyPage:當向 page()傳遞一個有效值,但是該頁面里沒有數據時拋出 Page對象 創建對象 Paginator對象的 page()方法返回得到Page對象 不需要手動創建 屬性 object_list:當前頁上所有數據(對象)列表 number:當前頁面的頁碼值 paginator:當前page對象關聯的paginator對象 方法 has_next() 判斷是否有下一頁,如果有返回 True has_previous() 判斷是否有上一頁,如果有返回 True has_other_pages() 判斷是否有上一頁或者下一頁,如果有返回 True next_page_number() 返回下一頁的頁碼,如果下一頁不存在拋出InvalidPage異常 previous_page_number() 返回上一頁的頁碼,如果上一頁不存在,拋出InvalidPage異常 len() 返回當前頁的數據(對象)個數 Paginator與Page對象關系(略) 代碼示例: 配置路由:url(r'^studentpage/(\d+)/$', views.studentpage), 配置視圖: from .models import Students from django.core.paginator import Paginator def studentpage(request, pageid): # 所有學生列表 allList = Students.objects.all() paginator = Paginator(allList, 6) page = paginator.page(pageid) return render(request, 'myApp/studentpage.html', {"students": page}) 配置html studentpage.html中body標簽中的內容: <body> <ul> {% for stu in students %} <li> {{stu.sname}}--{{stu.sgrade}} </li> {% endfor %} </ul> <ul> {% for index in students.paginator.page_range %} {% if index == students.number %} <li> {{index}} </li> {% else %} <li> <a href="/sunck/studentpage/{{index}}">{{index}}</a> </li> {% endif %} {% endif%} </ul> </body> ============================================================================== ajax 需要動態生成,請求JSON數據 代碼示例 ajaxstudents.html頁面示例 <script type="text/javascript" src="/static/myApp/js/jquery-3.1.1.min.js"></script> <body> <h1>學生信息列表</h1> <button id="btn">顯示學生信息</button> <script type="text/javascript" src="/static/myApp/js/sunck.js"></script> </body> sunck.js代碼示例 $(document).ready(function (){ document.getElementById("btn").onclick = function (){ $.ajax({ type:"get", url:"/studentsinfo/", dataType:"json", success:function(data, status){ console.log(data) var d = data["data"] for(var i=0; i<d.length; i++){ document.write('<p>' + d[i][0] + '</p>') } } }) } }) views.py代碼示例 def ajaxstudents(request): return render(request, 'myApp/ajaxstudents.html') from django.http import JsonResponse def studentsinfo(request): stus = Students.objects.all() list = [] for stu in stus: list.append([stu.sname, stu.sage]) return JsonResponse({"data":list}) ============================================================================== 富文本 pip install django-tinymce 在站點中使用 配置settings.py文件 INSTALLED_APPS 列表中添加 'tinymce', 增加 # 富文本 TINYMCE_DEFAULT_CONFIG = { 'theme':'advanced', 'width':600, 'height':400, } 創建一個模型類: 在models.py文件中增加 from tinymce.models import HTMLField class Text(models.Model): str = HTMLField() 配置站點: from .models import Text admin.site.register(Text) 自定義視圖使用 <head> <meta charset="UTF-8"> <title>富文本</title> <script type="text/javascript" src="/static/tiny_mce/tiny_mce.js"></script> <script type="text/javascript"> tinyMCE.init({ 'mode':'textareas', 'theme':'advanced', 'width':'800', 'height':'600', }) </script> </head> <body> <form action="/saveedit/" method="post"> <textarea name="str">sunck is a good man</textarea> <input type="submit" value="提交"/> </form> </body> Celery http://docs.jinkan.org/docs/celery/ 問題: 用戶發起request,並且要等待response返回,但在視圖中有一些耗時的操作, 導致用戶可能會等待很長時間才能接收response,這樣用戶體驗很差 網站每隔一段時間要同步一次數據,但是http請求是需要觸發的 解決: celery來解決 將耗時的操作放在celery中執行 使用celery定時執行 celery: 任務task 本質是一個Python函數,將耗時的操作封裝成一個函數 隊列queue 將要執行的任務放在隊列里 工人worker 負責執行對列中的任務 代理broker 負責高度,在部署環境中使用redis 安裝: pip install celery pip install celery-with-redis pip install django-celery 配置settings.py 在INSTALLED_APPS 列表中添加 'djcelery', # Celery import djcelery djcelery.setup_loader() # 初始化 BROKER_URL='redis://:sunck@127.0.0.1:6379/0' CELERY_IMPORTS=('myApp.task') 在應用目錄下創建task.py文件 遷移生成celery需要的數據庫表:python manage.py migrate 在工程目錄下的project目錄下創建celery.py文件 celery.py文件全部內容 from __future__ import absolute_import import os from celery import Celery from django.conf import settings os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'whthas_home.settings') app = Celery('portal') app.config_from_object('django.conf:settings') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) @app.task(bind=True) def debug_task(self): print('request: {0!r}'.format(self.request)) 在工程目錄下的 project目錄下的 __init__.py文件中添加