Python Day18 Django 04

Cookies參數

(1)獲取cookie

request.COOKIE

(2)設置cookie

response.set_cookie("","",)

(3)cookie參數

def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                   domain=None, secure=False, httponly=False):

max_age過期時間(秒)
expires過期時間(接收一個日期對象)
path 設置這個cookie在哪些路徑下有效 '/'代表在所有路徑下有效
domain 設置這個cookie在哪些域下有效

day12

session

設置session

request.session["user_id"]=user.pk
request.session["username"]=user.user

設置session方法及原理

第一步:
如果獲取到sessionid的值,則更新
if request.COOKIE.get("sessionid"):

第二步:
如果獲取不到,就創建一個字符串                  
{"user_id":1,"username":"alex"}

1. 生成隨機字符串: vwerascxh24asdasdasdsd(session-key)
2. 在django-sesion表生成一條記錄:
    session-key                    session-data
  vwerascxh24asdasdasdsd       {"user_id":1,"username":"alex"}

3. 設置Cookie
    obj.set_cookie("sessionid",vwerascxh24asdasdasdsd) 

這樣,下次再訪問時通過獲取cookie中的"sessionid"的值就可以得到所對應的session-data

django-sesion表中session記錄示例:

Python Day18 Django 04

獲取session方法及原理

獲取語句

request.session.get("user_id")

大概流程

1. 根據網頁所攜帶的cookie獲取"sessionid"的值
request.COOKIE.get("sessionid"):vwerascxh24asdasdasdsd

2. 根據"sessionid"的值在django-sesion表查詢一條記錄:
session-key=vwerascxh24asdasdasdsd

3. 獲取session-data中的數據
session-data({"user_id":1,"username":"alex"}).get("user_id")

示例:

def login(request):
    if request.method == "POST":
        user = request.POST.get("name")
        pwd = request.POST.get("pwd")
        user = Userinfo.objects.filter(user=user, pwd=pwd).first()
        res = {"msg": False}
        if user:
            res["msg"] = True
            import json
            obj = HttpResponse(json.dumps(res))
            request.session["user_id"] = user.pk     #設置session
            request.session["username"] = user.user  #設置session
            return obj

    return render(request, "login.html")
def index(request):
    if not request.session.get("user_id"):   #判斷是否能獲取到session
        return redirect("/login/")

    username = request.session.get("username")  #獲取session中"username"的值

    return render(request, "index.html", locals())  #把上面獲取到的username的值傳給模板

註銷session

def logout(request):

    request.session.flush()

    return redirect("/login/")

Django自帶分頁器

批量導入數據

在urls.py中創建一個url

url(r'^books/$', views.books)

在models中創建數據表

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)

在視圖中,方法1:

from django.shortcuts import render, HttpResponse

# Create your views here.
from app01.models import Book

def books(request):
    book_list = []
    for i in range(100):
        book_obj = Book(title="Book_%s" %i, price=i*i)
        book_list.append(book_obj)

    #會將上面的實例化對象一次插入到表中
    Book.objects.bulk_create(book_list)

    return HttpResponse("OK")

在視圖中,方法2:

#批量創建數據
objs = [models.Book(title="沙河{}".format(i)) for i in range(100)]

#在數據庫中批量創建,10次一提交
models.Book.objects.bulk_create(objs, 10)

訪問:
http://127.0.0.1:8000/books/

分頁器的使用

print("count:", paginator.count) # 數據總數
print("num_pages", paginator.num_pages) # 總頁數
print("page_range", paginator.page_range) # 頁碼的列表 返回一個range

page = paginator.page(2) #第2頁的page對象

print(page.object_list) #第2頁的所有數據
結果:

<QuerySet[ < Book: title_12 >, < Book: title_13 >, < Book: title_14 >...

for i in page: #遍歷第1頁的所有數據對象
print(i)

結果:
title_12
title_13
title_14
title_15

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

拋錯
page=paginator.page(12) # error:EmptyPage
page=paginator.page("z") # error:PageNotAnInteger

views

from django.shortcuts import render, HttpResponse

from .models import Book
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger        
def index(request):
    # 分頁器的使用
    try:
        book_list = Book.objects.all()

        paginator = Paginator(book_list, 12)  # 獲得一個總的分頁器對象

        # 從url獲取page值,如果沒有獲取就默認1
        c_page = request.GET.get("page", 1)
        # 轉換爲int類型,不然template識別不了
        currentPage = int(c_page) # 轉換爲int類型,不然template識別不了
        # 獲取page對象
        page = paginator.page(c_page)

    except EmptyPage:
        page = paginator.page(1)

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

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>分頁器</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<ul>
    {% for book in page.object_list %}
        <p>{{ book.title }}:{{ book.price }}</p>
    {% endfor %}
</ul>

<nav aria-label="Page navigation">
  <ul class="pagination">
  {% if page.has_previous %}
      <li><a href="?page={{ c_page|add:-1 }}" aria-label="Previous">上一頁</a></li>
  {% else %}
      <li class="disabled"><a href="?page={{ c_page|add:-1 }}" aria-label="Previous">上一頁</a></li>
  {% endif %}

      {% for num in paginator.page_range %}
          {% if currentPage == num %}
              <li class="active"><a href="?page={{ num }}">{{ num }}</a></li>
          {% else %}
              <li><a href="?page={{ num }}">{{ num }}</a></li>
          {% endif %}
      {% endfor %}

  {% if page.has_next %}
      <li><a href="?page={{ c_page|add:+1 }}" aria-label="Next">下一頁</a></li>
  {% else %}
      <li class="disabled"><a href="?page={{ c_page|add:+1 }}" aria-label="Next">下一頁</a></li>
  {% endif %}

  </ul>
</nav>

</body>
</html>

顯示限定頁碼數

如果頁數過多怎麼辦?這裏保持只顯示10個頁碼
將template中的paginator.page_range(總頁數的列表)修改爲下面的pageRange,
因爲顯示頁數過多,我們這裏指定返還給template的頁碼數列表(range)

def index(request):

book_list=Book.objects.all()

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

#如果總頁數大於30
if paginator.num_pages>30:
    #如果當前頁面page的值-5還小於1
    if currentPage-5<1:
        #頁碼的列表爲1-10(pageRange返回給模板)
        pageRange=range(1,11)
    #如果當前頁面page的值+5大於總頁數
    elif currentPage+5>paginator.num_pages:
        #計算最大頁數-10頁的頁碼
        min_page = (paginator.num_pages + 1) - 10
        #計算當前頁面所需要減去的頁碼數
        page_num = currentPage - min_page
        #頁碼的列表爲“當前所在頁數-上面計算的頁數 至 總頁數+1”,正好湊齊10頁(pageRange返回給模板)
        pageRange=range(currentPage-page_num,paginator.num_pages+1)

    else:
        #頁碼的列表爲“當前所在頁數-5,到當前所在頁數+5”(pageRange返回給模板)
        pageRange=range(currentPage-5,currentPage+5)

else:
    #如果總頁數小於30,返回給模板實際的頁碼的列表
    pageRange=paginator.page_range

try:
    #獲取當前頁面對象
    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())

Python Day18 Django 04

中間件

Python Day18 Django 04

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

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

自定義中間件

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

process_request

process_view

process_exception

process_response

process_request,process_response

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

Python Day18 Django 04

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

settings
自定義中間件放在哪都可以

MIDDLEWARE = [
    '...Django默認的Middleware...'
    'app01.utils.mymiddlewares.M1',  #注意,不要忘了逗號
    'app01.utils.mymiddlewares.M2'
]

in views:

from django.shortcuts import render, HttpResponse

def index(request):
    print("index")
    return HttpResponse("OK")

in Mymiddlewares.py:

from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import HttpResponse

class M1(MiddlewareMixin):   #注意繼承MiddlewareMixin類
    def process_request(self, request):
        print("M1 process_request")

    def process_response(self, request, response):
        print("M1 process_response")
        return response      #process_response要返回一個response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("M2 process_request")

    def process_response(self, request, response):
        print("M2 process_response")
        return response

結果

M1 process_request
M2 process_request
index
M2 process_response
M1 process_response

注意,process_request帶有return的情況下會在滿足條件時原路返回,等於從中間攔截了,不再往下走。
如果 process_response的return不返回response而且是它的,同樣也會產生偷樑換柱的效果,返回給客戶端的結果將不會是 views中定義的結果

Django-form表單

數據校驗

首先在模板中創建一個簡單的表單,以獲得用戶名、郵箱、手機號等

<form action="" method="post" novalidate>
    {% csrf_token %}
    <p>用戶名 <input type="text" name="user"></p>
    <p>郵箱 <input type="email" name="email"></p>
    <p>手機號 <input type="text" name="tel"></p>
    <input type="submit">
</form>

此時我們要將用戶在網頁上填寫的內容在視圖中拿出來,並做判斷
之前我們是使用if request.POST.get取出後進行判斷的,這裏換成form表單,
方法就是在views新建一個Form類(需要繼承forms.Form)
views:

from django import forms

class UserForm(forms.Form):
    user=forms.CharField(min_length=5)  #最少5位
    tel=forms.CharField(max_length=8)   #最長不超過8位
    email=forms.EmailField()            #判斷是否是郵箱地址類型

#我們通過上面這個類幫助我們進行數據校驗,從而實現功能的分離和複用
def reg(request):

    if request.method == "POST":
        form = UserForm(request.POST) #綁定數據至表單
        if form.is_valid(): 如果form.is_valid()爲Ture
            return HttpResponse('OK')
        else:
            return render(request, 'reg.html', {"form": form})

    return render(request, 'reg.html')

表單的is_valid()方法,如果被校驗的字段有一個錯誤,那麼就會返回False

備註:

在表單中輸入內容,看print(request.POST)能打印出什麼
<QueryDict: {
 'csrfmiddlewaretoken': ['Mhzbi6hiHnxVAKG9GEChEzscCo5GUnkuBnH3xmVOQGYfXxCTQUcoCiu9hGIiqRRT'],
 'user': ['dzm'],
 'email': ['[email protected]'],
 'tel': ['1118']
 }>

form表單數據校驗原理

會生成兩個字典

form.is_valid():
    # 校驗成功的字段
    form.cleaned_data={"user":"alex999","tel":'123'}

    # 校驗失敗的字段
    form.errors={"email":["..........","......."]} #列表中是錯誤信息,不再保留key原本的值

可以將他們打印出來
print("====>",form.cleaned_data)
print("====>",form.errors)
其它
print("---->", type(form.errors["user"])) #實際是個字典
print("---->", form.errors["user"][0]) #這樣可以取出具體的錯誤,然後返回給模板通過{{ form.errors.user.0 }}顯示出來

渲染標籤

form除了做校驗用還可以做標籤用(先拿到一個未綁定數據的form),生成的每個input標籤就是form類中字段的名字
views:

class UserForm(forms.Form):
    user = forms.CharField(       
        label="用戶名",   #自定義form表單顯示到網頁的名字
        min_length=5,
        error_messages={"required": "不能爲空", "min_length": "最小長度不能小於5"},  #自定義錯誤提示信息
        widget=widgets.TextInput(attrs={"class":"form-clontrol"})  #自定義屬性,添加一個Bootstrap樣式
    )

    tel=forms.CharField(label="手機號", max_length=8, widget=widgets.TextInput(attrs={"class": "form-control"}))
    email=forms.EmailField(label="郵箱", widget=widgets.TextInput(attrs={"class": "form-control"}))

Widgets

每個表單字段都有一個對應的Widget 類,它對應一個HTML 表單Widget,例如<input type="text">。

在大部分情況下,字段都具有一個合理的默認Widget。例如,默認情況下,CharField 具有一個TextInput Widget,它在HTML 中生成一個<input type="text">

表單渲染的選項

對於<label>/<input> 對,還有幾個輸出選項:

{{ form.as_table }} 以表格的形式將它們渲染在<tr> 標籤中
{{ form.as_p }} 將它們渲染在<p> 標籤中
{{ form.as_ul }} 將它們渲染在<li> 標籤中
注意,你必須自己提供<table> 或<ul> 元素。

模板:

{#方案1#}

{#<form action="" method="post" novalidate>#}
{#    {% csrf_token %}#}
{#    {{ form.as_p }}#}
{##}
{#    <input type="submit">#}
{#</form>#}

{#方案2#}

{#<form action="" method="post" novalidate>#}
{#    {% csrf_token %}#}
{#    <div>#}
{#        用戶名#}
{#        {{ form.user }}#}
{#    </div>#}
{##}
{#    <div>#}
{#        郵箱#}
{#        {{ form.email }}#}
{#    </div>#}
{#      <div>#}
{#        手機號#}
{#        {{ form.tel }}#}
{#    </div>#}
{#    #}
{#    <input type="submit">#}
{#</form>#}

方案3

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="" method="post" novalidate>
                {% csrf_token %}
                {% for filed in form %}
                <div>
                    <label for="">{{ filed.label }}</label>
                    {{ filed }}
                </div>
                {% endfor %}
                <input type="submit">
            </form>
        </div>
    </div>
</div>
</body>
</html>

更多內容:http://www.cnblogs.com/yuanchenqi/articles/7614921.html

用戶認證

用戶認證基於session,
用戶信息存儲在auth_user表中,
在命令行新建超級用戶:(manage.py)
createsuperuser

用戶登錄

def login(request):

    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        #校驗,將獲取到的用戶名和密碼與auth_user表中的記錄做比對,此時會將password轉換成加密信息再比對
        user = auth.authenticate(username=user, password=pwd) 
        #如果比對成功會返回一個User對象,失敗user會得到一個None

        if user:
            #可以獲得一個request.user對象,這個對象可以取到當前user對象所代表的用戶的所有信息
            auth.login(request, user)
            #此函數使用django的session框架給某個已認證的用戶附加上session id等信息。

            return redirect("/index/")  
        else:
            return redirect("/login/")

    return render(request, "login.html")

狀態保存驗證

def index(request):
    if not request.user:
        return redirect("/login/")

    #使用request.user獲取用戶名
    name = request.user.username
    return render(request, "index.html", {"name":name})

## 註銷
def logout(request):
    #這句話的本質還是調用request.session.flush()
    auth.logout(request)
    #當調用該函數時,當前請求的session信息會全部清除

    return redirect("/login/")

註冊(創建用戶)

def reg(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        #create_user創建一個普通用戶,
        User.objects.create_user(username=user, password=pwd)
        return redirect("/login/")

    return render(request, "reg.html")
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章