Django組件介紹
分頁器在頁面中非常常見,當數據庫條數數據過多時,頁面一次性顯示不好看,我們就可以使用頁面器,將數據分幾次顯示
一個簡單的分頁功能,可以導入用

page_num = request.GET.get('page','1') try: page_num = int(page_num) if page_num <=0: page_num = 1 except Exception as e: page_num =1 #總數量 all_count = len(userlist) #每頁顯示為10 頁 per_num = 10 #總頁碼數 total_page_num, more =divmod(all_count,per_num) if more: total_page_num += 1 #最多顯示的頁面數 max_show = 11 half_show = max_show//2 if total_page_num < max_show: page_start = 1 page_end = total_page_num elif page_num <= half_show: page_start =1 page_end =max_show elif page_num + half_show > total_page_num: page_start = total_page_num-max_show +1 page_end = total_page_num else: #起始頁面 page_start = page_num - half_show #終止頁面 page_end = page_num + half_show start =(page_num-1) * per_num end =page_num*per_num page_list = [] if page_num == 1: page_list.append('<li class="disabled"><a>上一頁</a></li>') else: page_list.append('<li ><a href="?page={}">上一頁</a></li>'.format(page_num - 1)) for i in range(page_start, page_end + 1): if i == page_num: page_list.append('<li class="active" ><a href="?page={}">{}</a></li>'.format(i, i)) else: page_list.append('<li><a href="?page={}">{}</a></li>'.format(i, i)) if page_num == total_page_num: page_list.append('<li class="disabled"><a>下一頁</a></li>') else: page_list.append('<li><a href="?page={}">下一頁</a></li>'.format(page_num + 1)) page_html = ''.join(page_list) return render(request, 'user_list.html', {'users': userlist[start:end], 'page_html': page_html})
django框架提供了一個form類,來處理web開發中的表單相關事項.form最常做的是對用戶輸入的內容進行驗證,為此django的forms類提供了全面的內容驗證和保留用戶上次輸入數據的支持
form組件的兩大功能:
---對用戶提交的內容進行驗證(from表單/ajax)
---表留用戶上次輸入的內容
form組件的幾大用處:
1.校驗字段功能

1.首先先到導入forms這個模塊 from django import forms 2.自己寫一個類,並繼承forms.Form class Myform(forms.Form): #這行代碼的意思,name這字段最長為8,最短為3 name=forms.charField(max_length=8) def index(request): dic={'name':'zh'} #這里就是類的實例化,傳的參數必須為一個字典 myform =Myform(dic) #這是對象的綁定方式,它的返回值就是一個布爾值 # True表示你傳的dic這個字典滿足form里的條件,False就是不滿足 # 我們可以通過判斷它,再進行邏輯操作,比如該字段符合你的要求,再怎么操作 if myform.is_valid(): return HttpResponse('校驗成功') # 走到這一步,代表當中有字段不符合要求 # 它的返回值是一個對象,但是它繼承了字典,所以你可以通過get取到錯誤提示 # 對了,你傳的字典的key值必須要和創建的類(Myform)要對應,並且只能多,不能少 # name_error = myform.errors.get('name') # 這樣你可以取到name字段出錯的原因了 name_error=myform.errors return HttpResponse('校驗失敗') ## 總結下:1、Myform的實例化必須傳字典 2、is_valid()返回值是布爾類型 3、errors 調用這個方法,返回值是對象,你可以通過get取值
2.渲染標簽功能
form組件可以在視圖函數中使用,也可以在模板中使用

渲染方式一: <form action='' method='post'> 用戶名:{{myform:name}} <br> <input type='submit' value = '提交'></input> </form> # 這里的{{myform:name}} 和你寫input框是一樣的效果,就是屬性比input框多一點 渲染方式二(推薦使用): <form action='' method='post'> {% for foo in myform%} {{ foo.lable }} : {{ foo }} <br> <input type='submit' value = '提交'></input> </form> # 頁面顯示都是一樣的,foo.lable不是用戶名,是name,但是你可以在創建Myform類時 # 在CharFiel中添加lable='用戶名',這樣就行了。 渲染方式三: <form action='' method='post'> {{ myform.as_p }} <input type='submit' value = '提交'></input> </form> # 對,方式三就是這么簡單,但是拓展性太差了,對不對,所以不推薦使用它
3.渲染錯誤信息功能

渲染錯誤信息,之前不是寫了error這個方法嘛,他就是裝着錯誤信息的對象, 其實就是讓它渲染到頁面上,這不就是很簡單嘛 拿渲染方式二來舉例子吧: <form action='' method='post'> {% for foo in myform%} {{ foo.lable }} : {{ foo }} <span>{{foo.errors.0}}</span><br> <input type='submit' value = '提交'></input> </form> # 來講下為什么不是用get去取錯誤信息,首先這個foo是什么?它就是你創建的字段 # 所以直接通過索引取值就好了,那么就應該知道foo.errors貌似就是一個列表對吧 # 模板渲染時我在后台渲染好了,再返回到前台的,那我可以不可以將錯誤信息傳到前台 # 讓前台執行DOM操作進行渲染呢? # 我覺得太麻煩,況且前端我。。。(你懂的)
4.組件的參數配置

其實在些Myform,下面的字段還有很多參數,我就寫寫大概有什么用 max_length # 代表該字段最長為多少 min_length # 代表該字段最短為多少 error_messages # 這是設置錯誤信息的屬性 # 例子 error_messages= {'max_length': '最長八位', 'min_length': '最短三位', 'required': '不能為空'} required # 默認值為True,意思是你傳來的字段必須有它,沒有的話校驗失敗 widget=widgets.TextInput() # 你在模板渲染的時候,就會渲染成Input框,type為text 還有其他類型的input框,自己在看看吧 對了,在TextInput(),你可以為input添加屬性,attrs={'class':'abc'} 寫在括號里面 lable #這個是不是上面講到了,lable='用戶名'
5.鈎子

局部鈎子 局部鈎子說白了就是寫一個函數,但是這個函數名必須為clean_name,這個name是可以改變的, 你定義的類里,你想對哪個字段寫鈎子函數,這個name就為那個字段的名字,比如我想為password這個 字段寫鈎子函數,那函數名就為clean_password,就這樣。 那這個局部鈎子有什么用了? 首先你的程序能走到局部鈎子這一步,就說明你傳的字典中的字段符合要求,這要記清楚,那么我們在 取值就從clean_data中取就好了,clean_data里裝的是符合要求的數據,是一個字典。 我們可以從clean_data中取到相應的值再做一次邏輯處理,比如我寫clean_name這個局部鈎子, 我可以拿到name,對這個name進行一些操作,名字開頭不能是數字,名字中不能有有什么字符,這 些等等,看你自己的需求,邏輯代碼寫好了,最后return name 就好了 全局鈎子 全局鈎子其實作用差不多的,每個字段你可以進行局部鈎子進行邏輯書寫,這些處理完成之后,有需要的話, 你再進行全局處理,舉個例子就大概能明白,你在寫注冊用戶的時候,是不是有密碼,確認密碼,你可以進行 布局鈎子處理,處理完畢是不是在進行判斷,判斷他們是否相等,相等的話,就存到數據庫中,不相等就拋個 異常,對了對了,上面局部鈎子忘記寫異常,下面講講。 -----1、局部鈎子,全局鈎子所拋出異常的類型為ValidationError,它是在下面這行代碼導入 from django.core.exceptions import ValidationError 2、局部鈎子拋出的異常會添加到該字段中的錯誤信息中,也就是myform.errors.get(字段名)中 3、而全局鈎子拋出的異常會添加到__all__中,myform.errors.get('__all__')中可以取到
作用:
1.手動對單表進行增,刪,改,查,手動把orm操作獲取的數據渲染到模塊;(階段1)
2.Form組件(類),自動生成標簽(input,select),並對用戶輸入的數據做規則驗證;(階段2)
3.ModelForm顧名思義就Form和Django的Model數據庫模型結合體,可以簡單,方便地對數據庫進行增加,編輯操作和驗證標簽的生成
使用ModelForm

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ form_obj.as_p }} {#<p>姓名:{{form_obj.name }}</p>#} </body> </html>

class BSForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for filed in self.fields.values(): if not isinstance(filed, forms.BooleanField): filed.widget.attrs.update({'class': "form-control"}) class RegForm(BSForm): re_pwd = forms.CharField(widget=forms.PasswordInput, label='確認密碼') class Meta: model = models.UserProfile fields='__all__' #獲取全部的 exclude=['memo','is_active'] #刪除不想要的 labels = { 'username': '用戶名' #標簽 } widgets = { 'password': forms.PasswordInput(attrs={'class': "form-control", 'k1': 'v1'}), } error_messages = { 'password': { 'required': '必填的' } } def clean(self): pwd = self.cleaned_data.get('password', '') re_pwd = self.cleaned_data.get('re_pwd', '') if pwd == re_pwd: return self.cleaned_data self.add_error('re_pwd', '兩次密碼不一致') raise ValidationError('兩次密碼不一直') def reg(request): form_obj=RegForm() if request.method =="POST": form_obj=RegForm(request.POST) if form_obj.is_valid(): # print(form_obj.cleaned_data) # form_obj.cleaned_data.pop('re_pwd') # models.UserProfile.objects.create(**form_obj.cleaned_data) form_obj.save() return redirect(reverse('login')) return render(request,'reg.html',{'form_obj':form_obj})
--MVC框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不需要依賴於特定的數據庫,通過簡單的配置就可以輕松更換數據庫
--ORM是'對象-關系-映射'的簡稱 ,主要任務是:
*根據對象的類型生成表結構
*將對象,列表的操作,轉換為sql語句
*將sql查詢到的結果轉換為對象,列表
--這極大地減輕了開發人員的工作量,不需要面對因數據庫變更而導致的無效勞動
--Django中的模型包含存儲數據的字段和約束,對應着數據庫中唯一的表

1.在models.py中定義模型類,要求繼承自models.Model 2.把應用加入settings.py文件的installed_app項 3.生成遷移文件 4.執行遷移生成表 5.使用模型類進行crud操作

在模型中定義屬性,會生成表中的字段
django根據屬性的類型確定以下信息:
當前選擇的數據庫支持字段的類型
渲染管理表單時使用的默認html控件
在管理站點最低限度的驗證
django會為表增加自動增長的主鍵列,每個模型只能有一個主鍵列,如果使用選項設置某屬性為主鍵列后,則django不會再生成默認的主鍵列
屬性命名限制
不能是python的保留關鍵字
由於django的查詢方式,不允許使用連續的下划線

定義屬性時,需要字段類型 字段類型被定義在django.db.models.fields目錄下,為了方便使用,被導入到django.db.models中 使用方式 導入from django.db import models 通過models.Field創建字段類型的對象,賦值給屬性 對於重要數據都做邏輯刪除,不做物理刪除,實現方法是定義isDelete屬性,類型為BooleanField,默認值為False 字段類型 AutoField:一個根據實際ID自動增長的IntegerField,通常不指定 如果不指定,一個主鍵字段將自動添加到模型中 BooleanField:true/false 字段,此字段的默認表單控制是CheckboxInput NullBooleanField:支持null、true、false三種值 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實例來表示的浮點數 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 blank:如果為True,則該字段允許為空白,默認值是 False 對比:null是數據庫范疇的概念,blank是表單驗證證范疇的 db_column:字段的名稱,如果未指定,則使用屬性的名稱 db_index:若值為 True, 則在表中會為此字段創建索引 default:默認值 primary_key:若為 True, 則該字段會成為模型的主鍵字段 unique:如果為 True, 這個字段在表中必須有唯一值 關系 關系的類型包括 ForeignKey:一對多,將字段定義在多的端中 ManyToManyField:多對多,將字段定義在兩端中 OneToOneField:一對一,將字段定義在任意一端中 可以維護遞歸的關聯關系,使用'self'指定,詳見“自關聯” 用一訪問多:對象.模型類小寫_set

增: models.UserInfo.object.create(name=new_name) 刪: models.UserInfo.object.get(id=xxx,None) models.delete() 改: obj = models.UserInfo.object.get(id=xx,None) obj = new_xxx obj.save() #相當於修改后提交數據 查 querylist=models.Entry.objects.all() print([e.title for e in querylist]) print([e.title for e in querylist]) entry = models.Entry.objects.get(id=?)
cookies是瀏覽器為web服務器存儲的一個信息,每次瀏覽器從某個服務器請求頁面時,都會自動帶上以前收到的cookie.cookie保存在客戶端,安全性較差,注意不要保存沒敢信息.
--網絡登錄
--購物車

def login(request): if request.method == 'GET': return render(request,'login2.html') if request.method == 'POST': u = request.POST.get('username') p = request.POST.get('pwd') dic = user_info.get(u) if not dic: return render(request,'login2.html') current_date = datetime.datetime.utcnow() current_date = current_date + datetime.timedelta(seconds=10) if dic['pwd'] == p: res = redirect('/myapp/index') # res.set_cookie('username',u,max_age=10) #對cookie設置了超時時間和安全設置 res.set_cookie('username',u,expires=current_date,httponly=True) # res.set_signed_cookie('username',u,salt="121221") return res else: return render(request,'login2.html')
詳情頁面,如果cookie 驗證通過則進入index頁面,否則刷新進入登錄頁面

def auth(func): def inner(request,*args,**kwargs): v = request.COOKIES.get('username') if not v: return redirect('/myapp/login') return func(request,*args,**kwargs) return inner @auth def index(request): v = request.COOKIES.get('username') return render(request,'index2.html',{'current_user':v})
session就是保存在后台數據或者緩存中的一個鍵值對,同樣的存儲着用戶信息,為更好的保護用戶隱私,其實是對前端cookie的一個升級的保護措施

當登錄成功后,會向后台數據庫 與 前端 Cookie同時發放一段隨機字符串,分別保存在后台的session中,前端 寫到用戶瀏覽器中,用戶下次登錄時候 拿着瀏覽器存着的sessionID當做KEY去后台數據庫中匹配進行驗證登錄即可拿到用戶相關信息,可以防止敏感信息直接暴露在瀏覽器上 作者:TianTianBaby223 鏈接:https://www.jianshu.com/p/a2d696364501 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。
Django下用session實現登錄驗證
def sessionLogin(request): if request.method == "GET": return render(request,'sessionLogin.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'root' and pwd =="123": #生成隨機字符串 #寫到用戶瀏覽器 #保存到session中 #在隨機字符串對應的字典中設置相關內容... request.session['username'] = user request.session['is_login'] = True if request.POST.get('rmb',None) == '1': request.session.set_expiry(10) return redirect('/myapp/sessionindex') else: return render(request, 'sessionLogin.html')
詳情頁邏輯
def sessionindex(request): #獲取當前用戶的隨機字符串 #根據隨機字符串獲取對應信息 if request.session.get('is_login',None): return render(request,'sessionindex.html',{'username':request.session['username']}) else: return HttpResponse('get out')
定義:介於request(請求)與response(響應)處理之間的一道處理過程,相對比較輕量級,位於web服務端與url路由層之間

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', #一些安全設置,比如xss腳本過濾
'django.contrib.sessions.middleware.SessionMiddleware',#session支持中間件,加入這個中間件,會在數據庫中生成一個django_session的表。
'django.middleware.common.CommonMiddleware', #通用中間件,會處理一些url
'django.middleware.csrf.CsrfViewMiddleware', #跨域請求偽造中間件,加入這個中間件,在提交表單的時候會必須加入csrf_token,cookie中也會生成一個名叫csrftoken的值,也會在header中加入一個HTTP_X_CSRFTOKEN的值來放置CSRF攻擊。
'django.contrib.auth.middleware.AuthenticationMiddleware', #用戶授權中間件。他會在每個HttpRequest對象到達view之前添加當前登錄用戶的user屬性,也就是你可以在view中通過request訪問user。
'django.contrib.messages.middleware.MessageMiddleware',#消息中間件。展示一些后台信息給前端頁面。如果需要用到消息,還需要在INSTALLED_APPS中添加django.contrib.message才能有效。如果不需要,可以把這兩個都刪除。
'django.middleware.clickjacking.XFrameOptionsMiddleware',#防止通過瀏覽器頁面跨Frame出現clickjacking(欺騙點擊)攻擊出現。
'A_orm.middlewares.auth.AuthenticationMiddleware',
]
請求進來是自上而下,通過反射找到類,用for循環來執行,可以自定義中間件,但也要寫入MIDDLEWAR中

1、process_request(self,request) #請求完執行 2、process_view(self, request, callback, callback_args, callback_kwargs) #如果有返回值,跳轉到最后一個中間件,執行最后一個中間件的response方法,逐步返回 3、process_template_response(self,request,response) #默認不執行,只有在視圖函數的返回對象中有render方法才會執行 4、process_exception(self, request, exception) #默認啥也不執行,在視圖函數出現錯誤是才執行,返回錯誤信息 5、process_response(self, request, response) #響應執行

1、做IP限制 放在 中間件類的列表中,阻止某些IP訪問了; 2、URL訪問過濾 如果用戶訪問的是login視圖(放過) 如果訪問其他視圖(需要檢測是不是有session已經有了放行,沒有返回login),這樣就省得在 多個視圖函數上寫裝飾器了! 3、緩存(還記得CDN嗎?) 客戶端請求來了,中間件去緩存看看有沒有數據,有直接返回給用戶,沒有再去邏輯層 執行視圖函數
執行順序:
1.我們要在app01文件下創建一個文件(middlewares)文件,在下面創建一個.py文件寫入自定義中間件
2.在setting里面添加中間件,文件路徑+功能
3.在views.py你們調用即可.
def index(request): print('1')
定義:用於框架執行操作時解耦,就是一些動作發生的時候,信號允許特定的發送者去提醒一些接受者

Model signals pre_init # django的model執行其構造方法前,自動觸發 post_init # django的model執行其構造方法后,自動觸發 pre_save # django的model對象保存前,自動觸發 post_save # django的model對象保存后,自動觸發 pre_delete # django的model對象刪除前,自動觸發 post_delete # django的model對象刪除后,自動觸發 m2m_changed # django的model中使用m2m字段操作第三張表(add,remove,clear)前后,自動觸發 class_prepared # 程序啟動時,檢測已注冊的app中modal類,對於每一個類,自動觸發 from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save

Management signals pre_migrate # 執行migrate命令前,自動觸發 post_migrate # 執行migrate命令后,自動觸發

Request/response signals request_started # 請求到來前,自動觸發 request_finished # 請求結束后,自動觸發 got_request_exception # 請求異常后,自動觸發 from django.core.signals import request_finished from django.core.signals import request_started

setting_changed # 使用test測試修改配置文件時,自動觸發 template_rendered # 使用test測試渲染模板時,自動觸發 from django.test.signals import setting_changed from django.test.signals import template_rendered

connection_created # 創建數據庫連接時,自動觸發 from django.db.backends.signals import connection_created