天天看點

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

分頁

Django的分頁器(paginator)

view

from django.shortcuts import render,HttpResponse

# Create your views here.
from app01.models import *
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def index(request):

    '''
    批量導入資料:

    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    '''

    '''
分頁器的使用:

    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #資料總數
    print("num_pages",paginator.num_pages)    #總頁數
    print("page_range",paginator.page_range)  #頁碼的清單



    page1=paginator.page(1) #第1頁的page對象
    for i in page1:         #周遊第1頁的所有資料對象
        print(i)

    print(page1.object_list) #第1頁的所有資料


    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一頁
    print(page2.next_page_number())    #下一頁的頁碼
    print(page2.has_previous())        #是否有上一頁
    print(page2.previous_page_number()) #上一頁的頁碼



    # 抛錯
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger

    '''


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)
    page = request.GET.get('page',1)
    currentPage=int(page)


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})      

index.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" target="_blank" rel="external nofollow"  
    integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h4>分頁器</h4>
    <ul>

        {% for book in book_list %}
             <li>{{ book.title }} -----{{ book.price }}</li>
        {% endfor %}

     </ul>


    <ul class="pagination" id="pager">

                 {% if book_list.has_previous %}
                    <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}" target="_blank" rel="external nofollow" >上一頁</a></li>
                 {% else %}
                    <li class="previous disabled"><a href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >上一頁</a></li>
                 {% endif %}


                 {% for num in paginator.page_range %}

                     {% if num == currentPage %}
                       <li class="item active"><a href="/index/?page={{ num }}" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >{{ num }}</a></li>
                     {% else %}
                       <li class="item"><a href="/index/?page={{ num }}" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >{{ num }}</a></li>

                     {% endif %}
                 {% endfor %}



                 {% if book_list.has_next %}
                    <li class="next"><a href="/index/?page={{ book_list.next_page_number }}" target="_blank" rel="external nofollow" >下一頁</a></li>
                 {% else %}
                    <li class="next disabled"><a href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >下一頁</a></li>
                 {% endif %}

            </ul>
</div>



</body>
</html>      

擴充

def index(request):


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 15)
    page = request.GET.get('page',1)
    currentPage=int(page)

    #  如果頁數十分多時,換另外一種顯示方式
    if paginator.num_pages>30:

        if currentPage-5<1:
            pageRange=range(1,11)
        elif currentPage+5>paginator.num_pages:
            pageRange=range(currentPage-5,paginator.num_pages+1)

        else:
            pageRange=range(currentPage-5,currentPage+5)

    else:
        pageRange=paginator.page_range


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",locals())      

自定義分頁器

"""
分頁元件使用示例:

    obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info)
    page_user_list = USER_LIST[obj.start:obj.end]
    page_html = obj.page_html()

    return render(request,'index.html',{'users':page_user_list,'page_html':page_html})


"""


class Pagination(object):

    def __init__(self,current_page,all_count,base_url,per_page_num=2,pager_count=11):
        """
        封裝分頁相關資料
        :param current_page: 目前頁
        :param all_count:    資料庫中的資料總條數
        :param per_page_num: 每頁顯示的資料條數
        :param base_url: 分頁中顯示的URL字首
        :param pager_count:  最多顯示的頁碼個數
        """

        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page <1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        self.base_url = base_url

        # 總頁碼
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager


        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果總頁碼 < 11個:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 總頁碼  > 11
        else:
            # 目前頁如果<=頁面上最多顯示11/2個頁碼
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 目前頁大于5
            else:
                # 頁碼翻到最後
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []

        first_page = '<li><a href="%s?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >首頁</a></li>' % (self.base_url,1,)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >上一頁</a></li>'
        else:
            prev_page = '<li><a href="%s?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >上一頁</a></li>' % (self.base_url,self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="%s?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >%s</a></li>' % (self.base_url,i, i,)
            else:
                temp = '<li><a href="%s?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >%s</a></li>' % (self.base_url,i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >下一頁</a></li>'
        else:
            next_page = '<li><a href="%s?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >下一頁</a></li>' % (self.base_url,self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="%s?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >尾頁</a></li>' % (self.base_url,self.all_pager,)
        page_html_list.append(last_page)

        return ''.join(page_html_list)      

中間件

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

中間件的概念

中間件顧名思義,是介于request與response處理之間的一道處理過程,相對比較輕量級,并且在全局上改變django的輸入與輸出。因為改變的是全局,是以需要謹慎實用,用不好會影響到性能。

Django的中間件的定義:

1

Middleware 

is

a framework of hooks into Django’s request

/

response processing. <br>It’s a light, low

-

level “plugin” system 

for

globally altering Django’s 

input

or

output.

如果你想修改請求,例如被傳送到view中的HttpRequest對象。 或者你想修改view傳回的HttpResponse對象,這些都可以通過中間件來實作。

可能你還想在view執行之前做一些操作,這種情況就可以用 middleware來實作。

大家可能頻繁在view使用

request.user

吧。 Django想在每個view執行之前把user設定為request的屬性,于是就用了一個中間件來實作這個目标。是以Django提供了可以修改request 對象的中間件 

AuthenticationMiddleware

Django預設的

Middleware

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',
]      

每一個中間件都有具體的功能。

自定義中間件

中間件中一共有四個方法:

process_request

process_view

process_exception

process_response      

process_request,process_response

當使用者發起請求的時候會依次經過所有的的中間件,這個時候的請求時process_request,最後到達views的函數中,views函數處理後,在依次穿過中間件,這個時候是process_response,最後傳回給請求者。

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

上述截圖中的中間件都是django中的,我們也可以自己定義一個中間件,我們可以自己寫一個類,但是必須繼承MiddlewareMixin

需要導入

1

from

django.utils.deprecation 

import

MiddlewareMixin

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

in views:

def index(request):

    print("view函數...")
    return HttpResponse("OK")      

in Mymiddlewares.py:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
 
    def process_response(self,request,response):
        print("Md1傳回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        #return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2傳回")
        return response      

結果:

Md1請求
Md2請求
view函數...
Md2傳回
Md1傳回      

注意:如果當請求到達請求2的時候直接不符合條件傳回,即return HttpResponse("Md2中斷"),程式将把請求直接發給中間件2傳回,然後依次傳回到請求者,結果如下:

傳回Md2中斷的頁面,背景列印如下:

Md1請求
Md2請求
Md2傳回
Md1傳回      

流程圖如下:

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

process_view

1

process_view(

self

, request, callback, callback_args, callback_kwargs)

 Mymiddlewares.py修改如下

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1傳回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md1view")

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2傳回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md2view")      

結果如下:

Md1請求
Md2請求
Md1view
Md2view
view函數...
Md2傳回
Md1傳回      

下圖進行分析上面的過程:

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

當最後一個中間的process_request到達路由關系映射之後,傳回到中間件1的process_view,然後依次往下,到達views函數,最後通過process_response依次傳回到達使用者。

process_view可以用來調用視圖函數:

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1傳回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        response=callback(request,*callback_args,**callback_kwargs)
        return response      

結果如下:

Md1請求
Md2請求
view函數...
Md2傳回
Md1傳回      

注意:process_view如果有傳回值,會越過其他的process_view以及視圖函數,但是所有的process_response都還會執行。

process_exception

1

process_exception(

self

, request, exception)

示例修改如下:

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1傳回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        # response=callback(request,*callback_args,**callback_kwargs)
        # return response
        print("md1 process_view...")

    def process_exception(self):
        print("md1 process_exception...")



class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        # return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2傳回")
        return response
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("md2 process_view...")

    def process_exception(self):
        print("md1 process_exception...")      

結果如下:

Md1請求
Md2請求
md1 process_view...
md2 process_view...
view函數...

Md2傳回
Md1傳回      

流程圖如下:

當views出現錯誤時:

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

 将md2的process_exception修改如下:

def process_exception(self,request,exception):

        print("md2 process_exception...")
        return HttpResponse("error")      

結果如下:

Md1請求
Md2請求
md1 process_view...
md2 process_view...
view函數...
md2 process_exception...
Md2傳回
Md1傳回      

Django實作的SESSION

1、 基本操作

1 2 3 4 5 6 7 8

1

、設定Sessions值

request.session[

'session_name'

=

"admin"

2

、擷取Sessions值

session_name 

=

request.session[

"session_name"

]

3

、删除Sessions值

del

request.session[

"session_name"

]

4

、檢測是否操作session值

if

"session_name"

is

request.session :

1、 基本操作

1 2 3 4 5 6 7 8

1

、設定Sessions值

request.session[

'session_name'

=

"admin"

2

、擷取Sessions值

session_name 

=

request.session[

"session_name"

]

3

、删除Sessions值

del

request.session[

"session_name"

]

4

、檢測是否操作session值

if

"session_name"

is

request.session :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

5

、get(key, default

=

None

)

fav_color 

=

request.session.get(

'fav_color'

'red'

)

6

、pop(key)

fav_color 

=

request.session.pop(

'fav_color'

)

7

、keys()

8

、items()

9

、setdefault()

10

、flush() 删除目前的會話資料并删除會話的Cookie。

這用于確定前面的會話資料不可以再次被使用者的浏覽器通路

例如,django.contrib.auth.logout() 函數中就會調用它。

11

使用者session的随機字元串

request.session.session_key

# 将所有Session失效日期小于目前日期的資料删除

request.session.clear_expired()

# 檢查 使用者session的随機字元串 在資料庫中是否

request.session.exists(

"session_key"

)

# 删除目前使用者的所有Session資料

request.session.delete(

"session_key"

)

request.session.set_expiry(value)

*

如果value是個整數,session會在些秒數後失效。

*

如果value是個datatime或timedelta,session就會在這個時間後失效。

*

如果value是

,使用者關閉浏覽器session就會失效。

*

如果value是

None

,session會依賴全局session失效政策。

2、 流程解析圖

Python學習-基礎篇17 Django-進階分頁中間件使用者認證 建構一個表單在Django 中建構一個表單Django Form 類詳解使用表單模闆

 3、 示例

views:

def log_in(request):

    if request.method=="POST": username=request.POST['user'] password=request.POST['pwd'] user=UserInfo.objects.filter(username=username,password=password) if user: #設定session内部的字典内容 request.session['is_login']='true' request.session['username']=username #登入成功就将url重定向到背景的url return redirect('/backend/') #登入不成功或第一通路就停留在登入頁面 return render(request,'login.html') def backend(request): print(request.session,"------cookie") print(request.COOKIES,'-------session') """ 這裡必須用讀取字典的get()方法把is_login的value預設設定為False, 當使用者通路backend這個url先嘗試擷取這個浏覽器對應的session中的 is_login的值。如果對方登入成功的話,在login裡就已經把is_login 的值修改為了True,反之這個值就是False的 """ is_login=request.session.get('is_login',False) #如果為真,就說明使用者是正常登陸的 if is_login: #擷取字典的内容并傳入頁面檔案 cookie_content=request.COOKIES session_content=request.session username=request.session['username'] return render(request,'backend.html',locals()) else: """ 如果通路的時候沒有攜帶正确的session, 就直接被重定向url回login頁面 """ return redirect('/login/') def log_out(request): """ 直接通過request.session['is_login']回去傳回的時候, 如果is_login對應的value值不存在會導緻程式異常。是以 需要做異常處理 """ try: #删除is_login對應的value值 del request.session['is_login'] # OR---->request.session.flush() # 删除django-session表中的對應一行記錄 except KeyError: pass #點選登出之後,直接重定向回登入頁面 return redirect('/login/')      

template:

===================================login.html==================
<!DOCTYPE html>
<html > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post"> <p>使用者名: <input type="text" name="user"></p> <p>密碼: <input type="password" name="pwd"></p> <p><input type="submit"></p> </form> </body> </html> ===================================backend.html================== <!DOCTYPE html> <html > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>hello {{ username }}</h3> <a href="/logout/" target="_blank" rel="external nofollow" >登出</a> </body> </html>      

4、session存儲的相關配置

(1)資料庫配置(預設):

Django預設支援Session,并且預設是将Session資料存儲在資料庫中,即:django_session 表中。

a. 配置 settings.py

SESSION_ENGINE 

=

'django.contrib.sessions.backends.db'

# 引擎(預設)

SESSION_COOKIE_NAME = 

"sessionid"

# Session的cookie儲存在浏覽器上時的key,即:sessionid=随機字元串(預設)

SESSION_COOKIE_PATH = 

"/"

# Session的cookie儲存的路徑(預設)

SESSION_COOKIE_DOMAIN 

=

None

# Session的cookie儲存的域名(預設)

SESSION_COOKIE_SECURE 

=

False

# 是否Https傳輸cookie(預設)

SESSION_COOKIE_HTTPONLY 

=

True

# 是否Session的cookie隻支援http傳輸(預設)

SESSION_COOKIE_AGE 

=

1209600

# Session的cookie失效日期(2周)(預設)

SESSION_EXPIRE_AT_BROWSER_CLOSE 

=

False

# 是否關閉浏覽器使得Session過期(預設)

SESSION_SAVE_EVERY_REQUEST 

=

False

# 是否每次請求都儲存Session,預設修改之後才儲存(預設)

2)緩存配置 

a. 配置 settings.py

SESSION_ENGINE 

=

'django.contrib.sessions.backends.cache'

# 引擎

SESSION_CACHE_ALIAS 

=

'default'

# 使用的緩存别名(預設記憶體緩存,也可以是memcache),此處别名依賴緩存的設定

SESSION_COOKIE_NAME = 

"sessionid"

# Session的cookie儲存在浏覽器上時的key,即:sessionid=随機字元串

SESSION_COOKIE_PATH = 

"/"

# Session的cookie儲存的路徑

SESSION_COOKIE_DOMAIN 

=

None

# Session的cookie儲存的域名

SESSION_COOKIE_SECURE 

=

False

# 是否Https傳輸cookie

SESSION_COOKIE_HTTPONLY 

=

True

# 是否Session的cookie隻支援http傳輸

SESSION_COOKIE_AGE 

=

1209600

# Session的cookie失效日期(2周)

SESSION_EXPIRE_AT_BROWSER_CLOSE 

=

False

# 是否關閉浏覽器使得Session過期

SESSION_SAVE_EVERY_REQUEST 

=

False

# 是否每次請求都儲存Session,預設修改之後才儲存

(3)檔案配置

a. 配置 settings.py

SESSION_ENGINE 

=

'django.contrib.sessions.backends.file'

# 引擎

SESSION_FILE_PATH 

=

None

# 緩存檔案路徑,如果為None,則使用tempfile子產品擷取一個臨時位址tempfile.gettempdir()        

SESSION_COOKIE_NAME = 

"sessionid"

# Session的cookie儲存在浏覽器上時的key,即:sessionid=随機字元串

SESSION_COOKIE_PATH = 

"/"

# Session的cookie儲存的路徑

SESSION_COOKIE_DOMAIN 

=

None

# Session的cookie儲存的域名

SESSION_COOKIE_SECURE 

=

False

# 是否Https傳輸cookie

SESSION_COOKIE_HTTPONLY 

=

True

# 是否Session的cookie隻支援http傳輸

SESSION_COOKIE_AGE 

=

1209600

# Session的cookie失效日期(2周)

SESSION_EXPIRE_AT_BROWSER_CLOSE 

=

False

# 是否關閉浏覽器使得Session過期

SESSION_SAVE_EVERY_REQUEST 

=

False

# 是否每次請求都儲存Session,預設修改之後才儲存

使用者認證 

auth子產品

1

from

django.contrib 

import

auth

django.contrib.auth中提供了許多方法,這裡主要介紹其中的三個:

1 、authenticate()   

提供了使用者認證,即驗證使用者名以及密碼是否正确,一般需要username  password兩個關鍵字參數

如果認證資訊有效,會傳回一個  User  對象。authenticate()會在User 對象上設定一個屬性辨別那種認證後端認證了該使用者,且該資訊在後面的登入過程中是需要的。當我們試圖登陸一個從資料庫中直接取出來不經過authenticate()的User對象會報錯的!!

1

user 

=

authenticate(username

=

'someone'

,password

=

'somepassword'

)

2 、login(HttpRequest, user)  

該函數接受一個HttpRequest對象,以及一個認證了的User對象

此函數使用django的session架構給某個已認證的使用者附加上session id等資訊。

1 2 3 4 5 6 7 8 9 10 11 12 13

from

django.contrib.auth 

import

authenticate, login

def

my_view(request):

username 

=

request.POST[

'username'

]

password 

=

request.POST[

'password'

]

user 

=

authenticate(username

=

username, password

=

password)

if

user 

is

not

None

:

login(request, user)

# Redirect to a success page.

...

else

:

# Return an 'invalid login' error message.

...

3 、logout(request) 登出使用者  

1 2 3 4 5

from

django.contrib.auth 

import

logout

def

logout_view(request):

logout(request)

# Redirect to a success page.

該函數接受一個HttpRequest對象,無傳回值。當調用該函數時,目前請求的session資訊會全部清除。該使用者即使沒有登入,使用該函數也不會報錯。

4 、user對象的 is_authenticated()

要求:

1  使用者登陸後才能通路某些頁面,

2  如果使用者沒有登入就通路該頁面的話直接跳到登入頁面

3  使用者在跳轉的登陸界面中完成登陸後,自動通路跳轉到之前通路的位址

方法1:

1 2 3

def

my_view(request):

if

not

request.user.is_authenticated():

return

redirect(

'%s?next=%s'

%

(settings.LOGIN_URL, request.path))

方法2:

django已經為我們設計好了一個用于此種情況的裝飾器:login_requierd()

1 2 3 4 5

from

django.contrib.auth.decorators 

import

login_required

@login_required

def

my_view(request):

...

若使用者沒有登入,則會跳轉到django預設的 登入URL '/accounts/login/ ' (這個值可以在settings檔案中通過LOGIN_URL進行修改)。并傳遞  目前通路url的絕對路徑 (登陸成功後,會重定向到該路徑)。

User對象

User 對象屬性:username, password(必填項)password用雜湊演算法儲存到資料庫

is_staff : 使用者是否擁有網站的管理權限.

is_active : 是否允許使用者登入, 設定為``False``,可以不用删除使用者來禁止 使用者登入

2.1 、is_authenticated()

如果是真正的 User 對象,傳回值恒為 True 。 用于檢查使用者是否已經通過了認證。

通過認證并不意味着使用者擁有任何權限,甚至也不檢查該使用者是否處于激活狀态,這隻是表明使用者成功的通過了認證。 這個方法很重要, 在背景用request.user.is_authenticated()判斷使用者是否已經登入,如果true則可以向前台展示request.user.name

2.2 、建立使用者

使用 create_user 輔助函數建立使用者:

1 2

from

django.contrib.auth.models 

import

User

user 

=

User.objects.create_user(username

=

'

',password='

',email='

')

2.3 、check_password(passwd)

1

使用者需要修改密碼的時候 首先要讓他輸入原來的密碼 ,如果給定的字元串通過了密碼檢查,傳回 

True

2.4 、修改密碼

使用 set_password() 來修改密碼

1 2 3

user 

=

User.objects.get(username

=

'')

user.set_password(password

=

'')

user.save 

2.5 、簡單示例

注冊:

def

sign_up(request):

state 

=

None

if

request.method 

=

=

'POST'

:

password 

=

request.POST.get(

'password'

, '')

repeat_password 

=

request.POST.get(

'repeat_password'

, '')

email

=

request.POST.get(

'email'

, '')

username 

=

request.POST.get(

'username'

, '')

if

User.objects.

filter

(username

=

username):

state 

=

'user_exist'

else

:

new_user 

=

User.objects.create_user(username

=

username, password

=

password,email

=

email)

new_user.save()

return

redirect(

'/book/'

)

content 

=

{

'state'

: state,

'user'

None

,

}

return

render(request, 

'sign_up.html'

, content)  

修改密碼:

@login_required

def

set_password(request):

user 

=

request.user

state 

=

None

if

request.method 

=

=

'POST'

:

old_password 

=

request.POST.get(

'old_password'

, '')

new_password 

=

request.POST.get(

'new_password'

, '')

repeat_password 

=

request.POST.get(

'repeat_password'

, '')

if

user.check_password(old_password):

if

not

new_password:

state 

=

'empty'

elif

new_password !

=

repeat_password:

state 

=

'repeat_error'

else

:

user.set_password(new_password)

user.save()

return

redirect(

"/log_in/"

)

else

:

state 

=

'password_error'

content 

=

{

'user'

: user,

'state'

: state,

}

return

render(request, 

'set_password.html'

, content)

建構一個表單

假設你想在你的網站上建立一個簡單的表單,以獲得使用者的名字。你需要類似這樣的模闆:

<form 

action

=

"/your-name/"

method=

"post"

>

<label 

for

=

"your_name"

>Your 

name

: </label>

<input id=

"your_name"

type=

"text"

name

=

"your_name"

>

<input type=

"submit"

value=

"OK"

>

</form>

這是一個非常簡單的表單。實際應用中,一個表單可能包含幾十上百個字段,其中大部分需要預填充,而且我們預料到使用者将來回編輯-送出幾次才能完成操作。

我們可能需要在表單送出之前,在浏覽器端作一些驗證。我們可能想使用非常複雜的字段,以允許使用者做類似從月曆中挑選日期這樣的事情,等等。

這個時候,讓Django 來為我們完成大部分工作是很容易的。

so,兩個突出優點:

    1 form表單送出時,資料出現錯誤,傳回的頁面中仍可以保留之前輸入的資料。

    2 友善地限制字段條件

在Django 中建構一個表單

Form 類

我們已經計劃好了我們的 HTML 表單應該呈現的樣子。在Django 中,我們的起始點是這裡:

#forms.py

from

django import forms

class NameForm(forms.Form):

your_name = forms.CharField(label=

'Your name'

, max_length=100)

 它定義一個

Form

 類,隻帶有一個字段(

your_name

)。

字段允許的最大長度通過

max_length

 定義。它完成兩件事情。首先,它在HTML 的

<input>

 上放置一個

maxlength="100"

(這樣浏覽器将在第一時間阻止使用者輸入多于這個數目的字元)。它還意味着當Django 收到浏覽器發送過來的表單時,它将驗證資料的長度。

Form

 的執行個體具有一個

is_valid()

 方法,它為所有的字段運作驗證的程式。當調用這個方法時,如果所有的字段都包含合法的資料,它将:

  • 傳回

    True

  • 将表單的資料放到

    cleaned_data

    屬性中。

完整的表單,第一次渲染時,看上去将像:

<label 

for

=

"your_name"

>Your 

name

: </label>

<input id=

"your_name"

type=

"text"

name

=

"your_name"

maxlength=

"100"

>

 注意它不包含 

<form>

 标簽和送出按鈕。我們必須自己在模闆中提供它們。

視圖

發送給Django 網站的表單資料通過一個視圖處理,一般和釋出這個表單的是同一個視圖。這允許我們重用一些相同的邏輯。

當處理表單時,我們需要在視圖中執行個體化它:

#views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect

from .forms import NameForm

def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            return HttpResponseRedirect('/thanks/')

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    return render(request, 'name.html', {'form': form})      

如果通路視圖的是一個

GET

 請求,它将建立一個空的表單執行個體并将它放置到要渲染的模闆的上下文中。這是我們在第一個通路該URL 時預期發生的情況。

如果表單的送出使用

POST

 請求,那麼視圖将再次建立一個表單執行個體并使用請求中的資料填充它:

form = NameForm(request.POST)

。這叫做”綁定資料至表單“(它現在是一個綁定的表單)。

我們調用表單的

is_valid()

方法;如果它不為

True

,我們将帶着這個表單傳回到模闆。這時表單不再為空(未綁定),是以HTML 表單将用之前送出的資料填充,然後可以根據要求編輯并改正它。

如果

is_valid()

True

,我們将能夠在

cleaned_data

 屬性中找到所有合法的表單資料。在發送HTTP 重定向給浏覽器告訴它下一步的去向之前,我們可以用這個資料來更新資料庫或者做其它處理。

模闆

我們不需要在name.html 模闆中做很多工作。最簡單的例子是:

<form 

action

=

"/your-name/"

method=

"post"

>

{% csrf_token %}

{{ form }}

<input type=

"submit"

value=

"Submit"

/>

</form>

根據

{{ form }}

,所有的表單字段和它們的屬性将通過Django 的模闆語言拆分成HTML 标記 。

注:Django 原生支援一個簡單易用的跨站請求僞造的防護。當送出一個啟用CSRF 防護的

POST

 表單時,你必須使用上面例子中的

csrf_token

 模闆标簽。

現在我們有了一個可以工作的網頁表單,它通過Django Form 描述、通過視圖處理并渲染成一個HTML 

<form>

Django Form 類詳解

綁定的和未綁定的表單執行個體

綁定的和未綁定的表單 之間的差別非常重要:

  • 未綁定的表單沒有關聯的資料。當渲染給使用者時,它将為空或包含預設的值。
  • 綁定的表單具有送出的資料,是以可以用來檢驗資料是否合法。如果渲染一個不合法的綁定的表單,它将包含内聯的錯誤資訊,告訴使用者如何糾正資料。

字段詳解

考慮一個比上面的迷你示例更有用的一個表單,我們完成一個更加有用的系統資料庫單:

#forms.py

from django import forms

class RegisterForm(forms.Form):
    username = forms.CharField(max_length=100,
                               error_messages={"min_length":"最短為5個字元","required":"該字段不能為空"},
                               )
    password = forms.CharField(max_length=100,
                               widget=widgets.PasswordInput(attrs={"placeholder":"password"})
                                )

    telephone=forms.IntegerField(
        error_messages={
            "invalid":"格式錯誤"
        }

                                )


    gender=forms.CharField(
          initial=2,
          widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
             )

    email = forms.EmailField()
    is_married = forms.BooleanField(required=False)      

Widgets

每個表單字段都有一個對應的

Widget

 類,它對應一個HTML 表單

Widget

,例如

<input type="text">

在大部分情況下,字段都具有一個合理的預設Widget。例如,預設情況下,

CharField

 具有一個

TextInput Widget

,它在HTML 中生成一個

<input type="text">

字段的資料

不管表單送出的是什麼資料,一旦通過調用

is_valid()

 成功驗證(

is_valid()

 傳回

True

),驗證後的表單資料将位于

form.cleaned_data

 字典中。這些資料已經為你轉換好為Python 的類型。

注:此時,你依然可以從

request.POST

 中直接通路到未驗證的資料,但是通路驗證後的資料更好一些。

在上面的聯系表單示例中,is_married将是一個布爾值。類似地,

IntegerField

 和

FloatField

 字段分别将值轉換為Python 的

int

 和

float

使用表單模闆

你需要做的就是将表單執行個體放進模闆的上下文。如果你的表單在

Contex

t 中叫做

form

,那麼

{{ form }}

将正确地渲染它的

<label>

 和 

<input>

元素。

表單渲染的選項

對于

<label>/<input>

 對,還有幾個輸出選項:

  • {{ form.as_table }}

     以表格的形式将它們渲染在

    <tr>

     标簽中
  • {{ form.as_p }}

     将它們渲染在

    <p>

     标簽中
  • {{ form.as_ul }}

     将它們渲染在

    <li>

     标簽中

注意,你必須自己提供

<table>

 或

<ul>

 元素。

{{ form.as_p }}

會渲染如下:

<

form

action="">

<

p

>

<

label

for="id_username">Username:</

label

>

<

input

id="id_username" maxlength="100" name="username" type="text" required="">

</

p

>

<

p

>

<

label

for="id_password">Password:</

label

>

<

input

id="id_password" maxlength="100" name="password" placeholder="password" type="password" required="">

</

p

>

<

p

>

<

label

for="id_telephone">Telephone:</

label

> <

input

id="id_telephone" name="telephone" type="number" required="">

</

p

>

<

p

>

<

label

for="id_email">Email:</

label

> <

input

id="id_email" name="email" type="email" required="">

</

p

>

<

p

>

<

label

for="id_is_married">Is married:</

label

> <

input

id="id_is_married" name="is_married" type="checkbox">

</

p

>

<

input

type="submit" value="注冊">

</

form

>

手工渲染字段

我們沒有必要非要讓Django 來分拆表單的字段;如果我們喜歡,我們可以手工來做(例如,這樣允許重新對字段排序)。每個字段都是表單的一個屬性,可以使用

{{ form.name_of_field }}

 通路,并将在Django 模闆中正确地渲染。例如:

<

div

class="fieldWrapper">

{{ form.Username.errors }}

{{ form.Username.label_tag }}

{{ form.Username }}

</

div

>

渲染表單的錯誤資訊

1、

registerForm=RegisterForm(request.POST)

print(type(registerForm.errors))                      #<

class

'django.forms.utils.ErrorDict'>

print(type(registerForm.errors["username"]))          #<

class

'django.forms.utils.ErrorList'>

2、

使用

{{ form.name_of_field.errors }}

 顯示表單錯誤的一個清單,并渲染成一個

ul

。看上去可能像:

<

ul

class="errorlist">

<

li

>Sender is required.</

li

>

</

ul

>

form元件的鈎子

def foo(request):


    if request.method=="POST":

        regForm=RegForm(request.POST)

        if regForm.is_valid():
            pass
            # 可用資料: regForm.cleaned_data,
            # 将資料插入資料庫表中


        else:
            pass
            # 可用資料: regForm.errors
            # 可以利用模闆渲染講errors嵌套到頁面中傳回
            # 也可以打包到一個字典中,用于ajax傳回

    else:
        regForm=RegForm()
    return render(request,"register.html",{"regForm":regForm})

    

    '''
    執行個體化時:

        self.fields={
            "username":"字段規則對象",
            "password":"字段規則對象",

        }


    is_valid時:

        self._errors = {}
        self.cleaned_data = {}


        #局部鈎子:

        for name, field in self.fields.items():
              try:

                    value = field.clean(value)
                    self.cleaned_data[name] = value
                    if hasattr(self, 'clean_%s' % name):
                        value = getattr(self, 'clean_%s' % name)()
                        self.cleaned_data[name] = value
              except ValidationError as e:
                    self.add_error(name, e)

        # 全局鈎子:

        self.clean()     # def self.clean():return self.cleaned_data

        return  not self.errors    # True或者False


    '''      

form元件補充

1、Django内置字段如下:

Field
    required=True,               是否允許為空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标簽或顯示内容
    initial=None,                初始值
    help_text='', 幫助資訊(在标簽旁邊顯示) error_messages=None, 錯誤資訊 {'required': '不能為空', 'invalid': '格式錯誤'} show_hidden_initial=False, 是否在目前插件後面再加一個隐藏的且具有預設值的插件(可用于檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支援本地化 disabled=False, 是否可以編輯 label_suffix=None Label内容字尾 CharField(Field) max_length=None, 最大長度 min_length=None, 最小長度 strip=True 是否移除使用者輸入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 總長度 decimal_places=None, 小數位長度 BaseTemporalField(Field) input_formats=None 時間格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正規表達式 max_length=None, 最大長度 min_length=None, 最小長度 error_message=None, 忽略,錯誤資訊使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允許空檔案 ImageField(FileField) ... 注:需要PIL子產品,pip3 install Pillow 以上兩個字典使用時,需要注意兩點: - form表單中 enctype="multipart/form-data" - view函數中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,預設select插件 label=None, Label内容 initial=None, 初始值 help_text='', 幫助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查詢資料庫中的資料 empty_label="---------", # 預設空顯示内容 to_field_name=None, # HTML中value的值對應的字段 limit_choices_to=None # ModelForm中對queryset二次篩選  ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 對選中的值進行一次轉換 empty_value= '' 空值的預設值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 對選中的每一個值進行一次轉換 empty_value= '' 空值的預設值 ComboField(Field) fields=() 使用多個驗證,如下:即驗證最大長度20,又驗證郵箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象類,子類中可以實作聚合多個字典去比對一個值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式清單:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式清單:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 檔案選項,目錄下檔案顯示在頁面中 path, 檔案夾路徑 match=None, 正則比對 recursive=False, 遞歸下面的檔案夾 allow_files=True, 允許檔案 allow_folders=False, 允許檔案夾 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支援的IP格式 unpack_ipv4=False 解析ipv4位址,如果是::ffff:192.0.2.1時候,可解析為192.0.2.1, PS:protocol必須為both才能啟用 SlugField(CharField) 數字,字母,下劃線,減号(連字元) ... UUIDField(CharField) uuid類型 ...      

2、Django内置插件:

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget      

3、常用選擇插件:

# 單radio,值為字元串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 單radio,值為字元串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 單select,值為字元串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 單select,值為字元串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多選select,值為清單
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 單checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多選checkbox,值為清單
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )      

引入:

https://www.cnblogs.com/wupeiqi/articles/6144178.html

轉載于:https://www.cnblogs.com/zheng-xi/p/9020419.html