Django之內置組件


Django組件介紹

        分頁器的使用

        Form

        modelForm

        orm

        cookie和session

        中間件

        信號

 

1.分頁器的使用

分頁器在頁面中非常常見,當數據庫條數數據過多時,頁面一次性顯示不好看,我們就可以使用頁面器,將數據分幾次顯示

一個簡單的分頁功能,可以導入用

  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})
分頁

2.Form組件

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__')中可以取到
     
說明

3.ModelForm

作用:

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})
后端

4.orm

--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=?)
orm操作

5.cookie和session

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')

6.中間件

定義:介於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')

7.信號

定義:用於框架執行操作時解耦,就是一些動作發生的時候,信號允許特定的發送者去提醒一些接受者

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
Test signals
connection_created          # 創建數據庫連接時,自動觸發
from django.db.backends.signals import connection_created
Database Wrappers

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM