Django之模板


Django1.8.2中文文檔:Django1.8.2中文文檔

模板

模板注釋

單行注釋:

{# 注釋內容 #}

多行注釋:

{% comment %}
注釋內容
{% endcomment %}

注意,模板注釋和html注釋不同,html注釋后瀏覽器檢查還能看到朱時候的代碼,但模板注釋不能被看到。

 

模板的功能

產生html,控制頁面上展示的內容。模板文件不僅僅是一個html文件。
模板文件包含兩部分內容:
1)靜態內容:css,js,html。
2)動態內容:用於動態去產生一些網頁內容。通過模板語言來產生。

 

模板文件的使用

通常是在視圖函數中使用模板產生html內容返回給客戶端。
a)加載模板文件 loader.get_template
獲取模板文件的內容,產生一個模板對象。
b)定義模板上下文 RequeseContext
給模板文件傳遞數據。
c)模板渲染產生html頁面內容 render
用傳遞的數據替換相應的變量,產生一個替換后的標准的html內容。

不用render自己渲染模板示例/ 給一個函數使用templates模板

def index(request):
    # 1.加載模板文件,獲取一個模板對象
    temp = loader.get_template('booktest/index.html')
    # 2.定義模板上下文,給模板文件傳數據
    # context = RequestContext(request, {})  # 在django1.11中不能使用這種方法,只能直接定義一個字典
    context = {}
    # 3.模板渲染,產生一個替換后的html內容
    res_html = temp.render(context)
    # 4.返回應答
    return HttpResponse(res_html)

自定義render渲染模板示例/ 抽離出templates渲染函數給多個視圖函數使用

def my_render(request, template_path, context={}):
    # 1.加載模板文件,獲取一個模板對象
    temp = loader.get_template(template_path)
    # 2.定義模板上下文,給模板文件傳數據
    # context = RequestContext(request, context)
    # context = {}
    # 3.模板渲染,產生一個替換后的html內容
    res_html = temp.render(context)
    # 4.返回應答
    return HttpResponse(res_html)


def index(request):
    # return render(request, 'booktest/index.html')
    return my_render(request, 'booktest/index.html')

 

模板文件加載順序

1)首先去配置的模板目錄下面去找模板文件。
2)去INSTALLED_APPS下面的每個應用的templates去找模板文件,前提是應用中必須有templates文件夾。

# index2頁面未創建
def index2(request):
    """模板文件的加載順序"""
    return my_render(request, 'booktest/index2.html')

報錯結果

 

模板語言

模板語言簡稱為DTL。(Django Template Language)

模板變量

模板變量名是由數字,字母,下划線和點組成的,不能以下划線開頭。
使用模板變量:

{{模板變量名}}

模板變量的解析順序:
例如:{{ book.btitle }}

  • 1)首先把book當成一個字典,把btitle當成鍵名,進行取值book['btitle']
  • 2)把book當成一個對象,把btitle當成屬性,進行取值book.btitle
  • 3)把book當成一個對象,把btitle當成對象的方法,進行取值book.btitle

例如:{{book.0}}

  • 1)首先把book當成一個字典,把0當成鍵名,進行取值book[0]
  • 2)把book當成一個列表,把0當成下標,進行取值book[0]

如果解析失敗,則產生內容時用空字符串填充模板變量。
使用模板變量時,.前面的可能是一個字典,可能是一個對象,還可能是一個列表。

使用模板變量示例

模板變量函數

def temp_var(request):
    """模板變量"""
    my_dict = {"title": "字典鍵值"}
    my_list = [1, 2, 3]
    book = models.BookInfo.objects.get(id=1)
    # 定義模板上下文
    context = {'my_dict': my_dict, 'my_list': my_list, 'book': book}
    return render(request, 'booktest/temp_var.html', context)

模板變量html代碼(booktest/temp_var.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板變量</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
使用字典屬性:{{ my_dict.title }} <br>
使用列表元素:{{ my_list.1 }} <br>
使用對象屬性:{{ book.btitle }}
</body>
</html>

 

模板標簽

模板標簽使用格式:

{% 代碼段 %}

for循環:

{% for x in 列表 %}
# 列表不為空時執行
{% empty %}
# 列表為空時執行
{% endfor %}

可以通過{{ forloop.counter }}得到for循環遍歷到了第幾次。

if判斷:

{% if 條件 %}
{% elif 條件 %}
{% else %}
{% endif %}

 

關系比較操作符:> < >= <= == !=
注意:進行比較操作時,比較操作符兩邊必須有空格。

邏輯運算:not and or

django內置標簽與過濾器文檔:內置標簽與過濾器文檔 或者 https://yiyibooks.cn/xx/django_182/ref/templates/builtins.html

模板標簽使用示例

 函數

def temp_tags(request):
    """模板標簽"""
    books = models.BookInfo.objects.all()
    return render(request, 'booktest/temp_tags.html', {'books': books})

html代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板標簽</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        .red {background-color: red;}
        .blue {background-color: blue;}
        .gray {background-color: gray;}
    </style>
</head>
<body>
<h1>模板標簽</h1>

<ul>
    {% for book in books %}
        {% if book.id <= 2 %}
            <li class="red">{{ forloop.counter }}--{{ book.btitle }}</li>
        {% elif book.id <= 3 %}
            <li class="blue">{{ forloop.counter }}--{{ book.btitle }}</li>
        {% else %}
            <li class="gray">{{ forloop.counter }}--{{ book.btitle }}</li>
        {% endif %}
    {% endfor %}
</ul>

</body>
</html>
booktest/temp_tags.html

 

過濾器

過濾器其實就是python函數。

過濾器用於對模板變量進行操作。

  • date:改變日期的顯示格式。
  • length:求長度。字符串,列表.
  • default:設置模板變量的默認值。

格式:

模板變量|過濾器:參數

自定義過濾器。
自定義的過濾器函數,至少有一個參數,最多兩個

過濾器的使用示例

過濾器函數

def temp_filter(request):
    """模板過濾器"""
    books = models.BookInfo.objects.all()
    return render(request, 'booktest/temp_filter.html', {'books': books})

過濾器html代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板過濾器</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        .red {background-color: red;}
        .blue {background-color: blue;}
        .gray {background-color: gray;}
    </style>
</head>
<body>
<h1>模板標簽</h1>

<ul>
    {% for book in books %}
        {% if book.id <= 2 %}
            <li class="red">{{ book.btitle }}--{{ book.bpub_date|date:'Y-m-d' }}</li>
        {% else %}
            {#  加了length后,會將原來的圖書名編程圖書名長度的數字  #}
            <li class="gray">{{ book.btitle|length }}--{{ book.bpub_date }}</li>
        {% endif %}
    {% endfor %}
</ul>
default過濾器:
{#  如果content沒有值,則過濾器會顯示默認的值  #}
{{ content|default:"hello" }}

</body>
</html>
booktest/temp_filter.html

注意:過濾器中,冒號后不能加空格,
例如{{ book.bpub_date|date:'Y-m-d' }}是正確的,而{{ book.bpub_date|date: 'Y-m-d' }}是錯誤的。
否則會報錯,Could not parse the remainder: ': 'Y-m-d'' from 'book.bpub_date|date: 'Y-m-d''

 

自定義過濾器

自定義過濾器

  • 1.在自己的應用下面新建一個 templatetags 文件夾,名字固定;
  • 2.在templatetags文件夾下面新建一個py文件,名字自定義,比如filters.py;
  • 3.1.在文件中,引入Library類;
  • 3.2.創建一個Library類的對象;
  • 3.3.定義自己的函數,給函數添加裝飾器@register.filter進行過濾器裝飾;

使用自定義裝飾器

  • 1.在需要使用的html文件中導入自定義裝飾器文件,{% load filters %},即 load 文件名;
  • 2.使用過濾器;

自定義過濾器示例

import django.template

# 創建一個Library類的對象
register = django.template.Library()

@register.filter
def mod(num):
    """判斷num是否為偶數"""
    # 如果傳過來的num是偶數,則返回True,否則返回False
    return num % 2 == 0

在html代碼中使用模板過濾器

<!DOCTYPE html>
<html lang="en">
{% load filters %}
<head>
    <meta charset="UTF-8">
    <title>模板過濾器</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        .red {background-color: red;}
        .blue {background-color: blue;}
        .gray {background-color: gray;}
    </style>
</head>
<body>
<h1>模板標簽</h1>

<ul>
    {% for book in books %}
        {% if book.id|mod %}
            <li class="red">{{ book.id }}--{{ book.btitle }}--{{ book.bpub_date|date:'Y-m-d' }}</li>
        {% else %}
            <li class="gray">{{ book.btitle }}--{{ book.bpub_date }}</li>
        {% endif %}
    {% endfor %}
</ul>

</body>
</html>
html使用一個參數的過濾器

 

兩個參數的自定義過濾器

自定義過濾器

# 自定義的過濾器,最少有一個參數,最多有兩個參數
# 只有一個參數的話,由|前面的參數傳過來,兩個參數的話,:后面再跟一個參數
# 應注意過濾器參數的前后順序
@register.filter
def mod_val(num, val):
    """判斷num是否能把value整除"""
    return num % val == 0

html代碼

<!DOCTYPE html>
<html lang="en">
{% load filters %}
<head>
    <meta charset="UTF-8">
    <title>模板過濾器</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        .red {background-color: red;}
        .blue {background-color: blue;}
        .gray {background-color: gray;}
    </style>
</head>
<body>
<h1>模板標簽</h1>

<ul>
    {% for book in books %}
        {# {% if book.id <= 2 %} #}
        {# % if book.id|mod %} #}
        {% if book.id|mod_val:3 %}
            <li class="red">{{ book.id }}--{{ book.btitle }}--{{ book.bpub_date|date:'Y-m-d' }}</li>
        {% else %}
            {#  加了length后,會將原來的圖書名編程圖書名長度的數字  #}
            <li class="gray">{{ book.btitle|length }}--{{ book.bpub_date }}</li>
        {% endif %}
    {% endfor %}
</ul>
default過濾器:
{#  如果content沒有值,則過濾器會顯示默認的值  #}
{{ content|default:"hello" }}

</body>
</html>
html使用兩個參數的自定義過濾器

 

模板繼承

模板繼承也是為了重用html頁面內容。

 

在父模板里可以定義塊,使用標簽:

{% block 塊名 %}
  塊中間可以寫內容,也可以不寫
{% endblock 塊名%}

子模板去繼承父模板之后,可以重寫父模板中的某一塊的內容。
繼承格式:

{% extends 父模板文件路徑%}


{% block 塊名 %}
    {{ block.super}} #獲取父模板中塊的默認內容
    重寫的內容
{% endblock 塊名%}

 

模板繼承示例

 base/母模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}base模板文件的title{% endblock title %}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <h1>base模板的header</h1>
    
    {% block b1 %}
        <h2>base模板的block1</h2>
    {% endblock b1 %}
    
    {% block b2 %}
        <h2>base模板的block1</h2>
    {% endblock b2 %}
    
    <h1>base模板的footer</h1>
</body>
</html>

child/子模板

{% extends 'booktest/base.html' %}

{% block title %}child模板中的title{% endblock title %}

{% block b1 %}
    {{ block.super }}
    <h2>child模板的block1</h2>
{% endblock b1 %}

{% block b2 %}
    <h2>child模板的block2</h2>
{% endblock b2 %}

配套函數

def temp_inherit(request):
    """返回child模板繼承於base的文件"""
    return render(request, 'booktest/child.html')

在塊里面還可以寫塊,需要注意endblock后面跟 塊名 用以區分哪個塊結束。

 

html轉義

場景:編輯商品詳情信息,數據表中保存的是html內容。
在模板上下文中的html標記默認是會被轉義的。

小於號< 轉換為&lt;
大於號> 轉換為&gt;
單引號' 轉換為&#39;
雙引號" 轉換為 &quot;
與符號& 轉換為 &amp;

要關閉模板上下文字符串的轉義:可以使用

{{ 模板變量|safe}}

也可以使用:

{% autoescape off %}
模板語言代碼
{% endautoescape %}

模板硬編碼中的字符串默認不會經過轉義,如果需要轉義,那需要手動進行轉義。

safe和autoescape的區別在於,safe只能轉義一個模板變量,而autoescape可以轉義多個變量;

 

html轉義示例

html_escape.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板轉義</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
html轉義結果:<br>
{{ content }}<br>

使用safe過濾器關閉轉義結果:<br>
{{ content|safe }}<br>

使用autoescape關閉轉義結果:<br>
{% autoescape off %}
    {{ content }}
    {{ content }}
{% endautoescape %}<br>

模板硬編碼中的字符串默認不會轉義,即會經過html渲染:<br>
{{ test|default:'<h1>hello</h1>' }}<br>

手動對硬編碼進行轉義:<br>
{{ test|default:'&lt;h1&gt;hello&lt;/h1&gt;' }}
</body>
</html>

配套函數

# /html_escape
def html_escape(request):
    """模板轉義"""
    return render(request, 'booktest/html_escape.html', {'content': '<h1>hello</h1>'})

 

驗證碼

在用戶注冊、登錄頁面,為了防止暴力請求,可以加入驗證碼功能,
如果驗證碼錯誤,則不需要繼續處理,可以減輕業務服務器、數據庫服務器的壓力。

自實現驗證碼

安裝pillow

pip install Pillow==3.4.1

編寫函數/視圖

from PIL import Image, ImageDraw, ImageFont
from django.utils.six import BytesIO


def verify_code(request):
    # 引入隨機函數模塊
    import random
    # 定義變量,用於畫面的背景色、寬、高
    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), 255)
    width = 100
    height = 25
    # 創建畫面對象
    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)
    # 定義驗證碼的備選值
    str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
    # 隨機選取4個值作為驗證碼
    rand_str = ''
    for i in range(0, 4):
        rand_str += str1[random.randrange(0, len(str1))]
    # 構造字體對象,ubuntu的字體路徑為“/usr/share/fonts/truetype/freefont”
    font = ImageFont.truetype('FreeMono.ttf', 23)
    # 構造字體顏色
    fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 繪制4個字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
    # 釋放畫筆
    del draw
    # 存入session,用於做進一步驗證
    request.session['verifycode'] = rand_str
    # 內存文件操作
    buf = BytesIO()
    # 將圖片保存在內存中,文件類型為png
    im.save(buf, 'png')
    # 將內存中的圖片數據返回給客戶端,MIME類型為圖片png
    return HttpResponse(buf.getvalue(), 'image/png')
自實現驗證碼函數

查看驗證碼

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

在網頁中使用驗證碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="/login_check/" method="post">
    {% csrf_token %}
    用戶:<input type="text" id="username" name="username" value="{{ usernam }}"><br />
    密碼:<input type="password" id="password" name="password"><br />
    <input type="checkbox" name="remember">記住用戶名<br />
    <img src="/verify_code"> <input type="text" name="vcode"><br>

    <input type="submit" value="登錄">
</form>

</body>
</html>
html中使用驗證碼

登錄校驗驗證碼函數

def login_check(request):
    # 1.獲取用戶名和密碼
    username = request.POST.get("username")
    password = request.POST.get("password")
    remember = request.POST.get("remember")
    print(username, password)

    # 獲取用戶輸入的驗證碼
    vcode1 = request.POST.get('vcode')
    # 獲取session中保存的驗證碼
    vcode2 = request.session.get('verifycode')
    # 進行驗證碼校驗
    if vcode1 != vcode2:
        # 驗證碼錯誤
        return redirect('/login')

    # 2.進行校驗
    # 3.返回應答
    if username == "yifchan" and password == "yifchan":
        # response = redirect("/index")
        response = redirect("/change_pwd")
        # 判斷是否需要記住用戶名
        if remember == 'on':
            # 設置cookie username-過期時間為1周
            response.set_cookie('username', username, max_age=7 * 24 * 3600)
            # 記住用戶登錄狀態
            # 只有session中有islogin,就認為用戶已經登錄
            request.session['islogin'] = True
            request.session['username'] = username
        return response
    else:
        return HttpResponse("賬號或密碼錯誤")
驗證碼校驗函數

 

 

url反向解析

當某一個url配置的地址發生變化時,頁面上使用反向解析生成地址的位置不需要發生變化。
根據url 正則表達式的配置動態的生成url。


在項目urls中包含具體應用的urls文件時指定namespace;

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('booktest.urls', namespace='booktest')),
]

在應用的urls中配置是指定name;

urlpatterns = [
    url(r'^index/$', views.index, name='index'),

    url(r'^url_reverse/$', views.url_reverse),  #
    url(r'^show_args/(\d+)/(\d+)$', views.show_args, name='show_args'),  # 捕獲位置參數
    url(r'^show_kwargs/(?P<c>\d+)/(?P<d>\d+)$', views.show_kwargs, name='show_kwargs'),  # 捕獲關鍵字參數
]

在模板文件中使用時,格式如下:

{% url 'namespace名字:name' %} 例如{% url 'booktest:fan2' %}

帶位置參數:

{% url 'namespace名字:name' 參數 %} 例如{% url 'booktest:fan2' 1 %}

帶關鍵字參數:

{% url 'namespace名字:name' 關鍵字參數 %} 例如{% url 'booktest:fan2' id=1 %}

在視圖中/重定向的時候使用反向解析:

from django.core.urlresolvers import reverse

無參數:

reverse('namespace名字:name名字')

如果有位置參數

reverse('namespace名字:name名字', args = 位置參數元組)

如果有關鍵字參數

reverse('namespace名字:name名字', kwargs=字典)

 

url反向解析示例

項目下的url文件

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('booktest.urls', namespace='booktest')),
]

應用下的url文件

urlpatterns = [
    url(r'^index/$', views.index, name='index'),

    url(r'^url_reverse/$', views.url_reverse),  #
    url(r'^show_args/(\d+)/(\d+)$', views.show_args, name='show_args'),  # 捕獲位置參數
    url(r'^show_kwargs/(?P<c>\d+)/(?P<d>\d+)$', views.show_kwargs, name='show_kwargs'),  # 捕獲關鍵字參數
   url(r'^test_reverse/$', views.test_reverse, name='test_reverse'),  # 視圖使用反向解析
]

模板中使用url反向解析

配套函數

def url_reverse(request):
    return render(request, 'booktest/url_reverse.html')

def show_args(request, a, b):
    return HttpResponse(a+':'+b)

def show_kwargs(request, c, d):
    return HttpResponse(c+':'+d)

url_reverse.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>url反向解析</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    index鏈接:<br>
    <a href="/index">首頁</a><br>
    url反向解析生成index鏈接:<br>
    <a href="{% url 'booktest:index' %}">首頁</a><br>

    位置參數 /show_args/1/2:<br>
    <a href="/show_args/1/2">/show_args/1/2</a><br>
    動態生成/show_args/1/2:<br>
    <a href="{% url 'booktest:show_args' 1 2 %}">/show_args/1/2</a><br>

    關鍵字參數 /show_kwargs/3/4:<br>
    <a href="/show_kwargs/3/4">/show_args/3/4</a><br>
    動態生成/show_kwargs/3/4:<br>
    <a href="{% url 'booktest:show_kwargs' c=3 d=4 %}">/show_args/3/4</a><br>

</body>
</html>

 

視圖中使用反向解析
反向解析函數

from django.core.urlresolvers import reverse


# url: /test_reverse
def test_reverse(request):
    # 重定向到 /index
    # return redirect('/index')
    # url = reverse('booktest:index')

    # 重定向到位置參數 show_args/1/2
    # url = reverse('booktest:show_args', args=(1, 2))

    # 重定向到關鍵字參數 show_kwargs/3/4
    url = reverse('booktest:show_kwargs', kwargs={'c': 3, 'd': 4})

    return redirect(url)

 

csrf攻擊

首先做一個登錄頁,讓用戶輸入用戶名和密碼進行登錄,登錄成功之后跳轉的修改密碼頁面。在修改密碼頁面輸入新密碼,點擊確認按鈕完成密碼修改。
登錄頁需要一個模板文件login.html.修改密碼頁面也需要一個模板文件change_pwd.html.
顯示登錄頁的視圖login,驗證登錄的視圖login_check,顯示發帖頁的視圖change_pwd,處理修改密碼的視圖change_pwd_action.
加功能:
a)只有用戶登錄之后才可以進行修改密碼操作。
登錄裝飾器函數。

def login_required(view_func):
    """登錄判斷裝飾器"""
    def wrapper(request, *args, **kwargs):
        # 判斷用戶是否登錄
        if request.session.has_key('islogin'):
            # 已經登錄了,就返回到函數
            return view_func(request, *args, **kwargs)
        else:
            # 未登錄,返回到登錄頁面
            return redirect('/login')
    return wrapper

 

案例流程圖:

 

django防止csrf的方式:

  • 1) 默認打開csrf中間件。
  • 2) 表單post提交數據時加上{% csrf_token %}標簽。

防御原理:

  • 1)渲染模板文件時在頁面生成一個名字叫做csrfmiddlewaretoken的隱藏域。
  • 2)服務器交給瀏覽器保存一個名字為csrftoken的cookie信息。
  • 3)提交表單時,兩個值都會發給服務器,服務器進行比對,如果一樣,則csrf驗證通過,否則失敗。

 

登錄案例代碼

設計路由

url(r'^login/$', views.login), # 返回登錄頁面
url(r'^login_check/$', views.login_check), # 進行登錄校驗
url(r'^change_pwd/$', views.change_pwd), # 返回修改密碼頁面
url(r'^change_pwd_action/$', views.change_pwd_action), # 修改密碼處理函數

編寫login.html頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="/login_check/" method="post">
    <label for="username">用戶:
        <input type="text" id="username" name="username" value="{{ usernam }}">
    </label><br />

    <label for="password">密碼:
        <input type="password" id="password" name="password">
    </label><br />

    <input type="checkbox" name="remember">記住用戶名<br />

    <input type="submit" value="登錄">
</form>

</body>
</html>
login.html

編寫login函數

def login(request):
    """登錄處理函數"""
    # 判斷用戶是否登錄
    if request.session.has_key('islogin'):
        # return redirect('/index')
        return redirect('/change_pwd')
    else:
        # 獲取cookie username
        if 'username' in request.COOKIES:
            username = request.COOKIES['username']
        else:
            username = ''
        return render(request, "booktest/login.html", {'usernam': username})
login函數

編寫

def login_check(request):
    # 1.獲取用戶名和密碼
    username = request.POST.get("username")
    password = request.POST.get("password")
    remember = request.POST.get("remember")
    print(username, password)
    # 2.進行校驗
    # 3.返回應答
    if username == "yifchan" and password == "yifchan":
        # response = redirect("/index")
        response = redirect("/change_pwd")
        # 判斷是否需要記住用戶名
        if remember == 'on':
            # 設置cookie username-過期時間為1周
            response.set_cookie('username', username, max_age=7*24*3600)
            # 記住用戶登錄狀態
            # 只有session中有islogin,就認為用戶已經登錄
            request.session['islogin'] = True
            request.session['username'] = username
        return response
    else:
        return HttpResponse("賬號或密碼錯誤")
login_check函數

編寫change_pwd.html頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密碼</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="/change_pwd_action">
    新密碼:<input type="password" name="pwd">
    <input type="submit" value="確認修改">
</form>
</body>
</html>
change_pwd.html

編寫登錄判斷裝飾器

def login_required(view_func):
    """登錄判斷裝飾器"""
    def wrapper(request, *args, **kwargs):
        # 判斷用戶是否登錄
        if request.session.has_key('islogin'):
            # 已經登錄了,就返回到函數
            return view_func(request, *args, **kwargs)
        else:
            # 未登錄,返回到登錄頁面
            return redirect('/login')
    return wrapper
登錄判斷裝飾器

定義change_pwd函數

@login_required
def change_pwd(request):
    """顯示修改密碼頁面"""
    return render(request, 'booktest/change_pwd.html')
change_pwd函數

定義change_pwd_action函數

@login_required
def change_pwd_action(request):
    """模擬修改密碼處理"""
    # 1.獲取新密碼
    pwd = request.POST.get("pwd")
    # username = request.COOKIES['username']
    username = request.session.get('username')
    # 2.實際開發的時候,修改對應的數據庫中的數據
    # 3.返回應答
    return HttpResponse('%s修改密碼為:%s' % (username, pwd))
change_pwd_action函數

 

csrf偽造
django默認開啟csrf防護,並且只針對post提交;

  • 1.開啟csrf防護,把注釋的settings文件里面的csrf放開注釋;
  • 2.在要提交表單的地方,添加{% csrf_token %}

csrf防護示例代碼

login頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="/login_check/" method="post">
    {% csrf_token %}
    用戶:<input type="text" id="username" name="username" value="{{ usernam }}"><br />
    密碼:<input type="password" id="password" name="password"><br />
    <input type="checkbox" name="remember">記住用戶名<br />

    <input type="submit" value="登錄">
</form>

</body>
</html>
login.html

change_pwd頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密碼</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="/change_pwd_action/" method="post">
    {% csrf_token %}
    新密碼:<input type="password" name="pwd">
    <input type="submit" value="確認修改">
</form>
</body>
</html>
change_pwd.html

在模擬的時候,自制的第三方網站,可以拿到自己頁面的csrftoken隱藏域的信息,然后放到自己的第三方網站代碼去;
但在實際上,這樣很難實現。

 


免責聲明!

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



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