1. 程式人生 > >五 【用django2.0來開發】實現會員註冊功能

五 【用django2.0來開發】實現會員註冊功能

odi 記得 Language 會員 ffffff extends gist processor url跳轉

上一節我們完成了會員功能的後臺管理, 這一節我們需要完成會員註冊功能, 涉及到以下幾個模塊

  1. URL配置
  2. views視圖模塊
  3. 模板
  4. Request/Response對象的使用

項目地址:https://gitee.com/ccnv07/django_example

URL路由配置

django是通過項目的urls.py文件來定義網站的url路由, 在我們的項目中是cms/urls.py文件

django的基本訪問流程

  1. 訪問url時, 通過cms/urls.py中定義的url路由, 獲取到要執行的視圖函數或者類(保存在views.py)
  2. 將Request(請求對象)轉發到指定的視圖函數/類中, 執行視圖函數/類的代碼
  3. 通過模板渲染(沒有模板則是其他的JsonResponse等資源對象), 將結果數據返回並輸出到瀏覽器中

打開cms/urls.py文件

from django.contrib import admin
from django.urls import path
urlpatterns = [
    path(‘admin/‘, admin.site.urls),
]

urlpatterns是整個路由的一個list, 是django定義的固定名稱

path函數
path(route, view, kwargs=None, name=None)
route: 指定訪問的路由
view: 是指定訪問的視圖函數/類

name: 是指定這條路由的名稱, 通過這個名稱, 我們就可以生成一個可訪問的url

默認的這一條路由, 就是定義了整個後臺的訪問url, 都是以admin/開頭的url, django會將admin.site.urls中定義的路由都加載過來

比如我們之前做的後臺管理功能, url就是:/admin/account/account/

路由route參數的格式

1. 固定字符串路由

這種路由是固定訪問的url, 不會發生變化, 比如關於我的訪問頁面.

urlpatterns = [
    path(‘about/‘, views.about),
]

2. 帶有變量的url路由, 比如我們訪問指定欄目下的文章

urlpatterns = [
    path(‘list/<int:nav_id>‘, views.list),
]

這種應該用會比較多一些, <int:>指定這個nav_id必須是數字類型, 會執行類型強制轉換, 而nav_id就是參數名, 通過以下的方式, 就可以訪問到這個參數。

# views.py
def list(request, nav_id):
    pass

除了支持int, django的url路由也支持str,slug,uuid,path四種類型, 一般常用的也就是str和int

3. 正則表達式路由

from django.urls import path, re_path

from . import views

urlpatterns = [
    path(‘articles/2003/‘, views.special_case_2003),
    re_path(r‘^articles/(?P<year>[0-9]{4})/$‘, views.year_archive),
]

path函數定義的是普通的路由
re_path韓都定義正則路由, 參數完全一樣

像上面這個例子中的re_path, 每個()中就是一個參數的定義, ?P說明這裏定義的是一個參數, <year>是參數key, [0-9]{4}是正則表達式, $符代表路由結束, 不再往後匹配。
所以這個url可以匹配到articles/2018/ 這樣的url

urlpatterns = [
    re_path(r‘^comments/(?:page-(?P<page_number>\d+)/)?$‘, comments),  # good
]

在這個例子中, ?: 代表是這是一個字符串的url, page-並不是一個參數
所以匹配的url是comments/page-1 的url

4. 包含其他的路由

from django.urls import include, path
urlpatterns = [
    path(‘account/‘, include(‘account.urls‘)),
]

include
include(module, namespace=None)
include(pattern_list)
include((pattern_list, app_namespace), namespace=None)

module: urlconf的模塊
namespace: url入口的命名空間
pattern_list: 可以叠代的path()/re_path實例類
app_namespace: url入口的app的命名空間

之後會依次講, 一般我們常見的也就是include(‘account.urls‘))這種方式, 會將account/urls.py中定義的url路由都加載進來
一下就是在account/urls.py中定義的路由

# account/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path(‘index/‘, views.index, name=‘account-index‘)
]

根據以上的路由規則, 我們可訪問的url就是account/index/ 這個url

定義會員註冊的路由

將模塊路由文件加載進項目中

# cms/urls.py
import debug_toolbar
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
    path(‘admin/‘, admin.site.urls),
    path(‘account/‘, include(‘account.urls‘))
]

這樣關於會員模塊的url路由, 我們就都可以在account/urls.py文件中定義了。

在模塊中定義url路由

創建account/urls.py文件

# account/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path(‘register/‘, views.register, name=‘account-register‘)
]

View視圖模塊

視圖函數的定義

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

每個視圖函數都有一個固定的參數request, 這個是Request對象, 包含瀏覽器發起請求帶的參數, 包括常見的url, post數據, 請求類型, header頭等等。

然後視圖函數的返回也必須是一個Reponse對象, 一般我們返回的都是html代碼, 所以使用的是HttpResponse對象
有時候我們寫的是接口, 使用的是JsonResponse對象

視圖中最常用的函數

render 模板渲染函數

但是如果把html代碼寫在python文件中, 也太不好看了, 所以, 我們可以通過render函數來完成模板的渲染
render(request, template_name, context=None, content_type=None, status=None, using=None)

request: 是請求對象,
template_name: 模板文件名稱
context: 要傳遞給模板文件的變量
content_type: 文檔header頭中Content-Type的類型
status: http響應碼, 就是200, 301, 302, 400, 500那個
using: 要使用的模板引擎

from django.shortcuts import render

def my_view(request):
    # View code here...
    return render(request, ‘myapp/index.html‘, {
        ‘foo‘: ‘bar‘,
    }, content_type=‘application/xhtml+xml‘)

render會自動幫我們轉換成HttpResponse對象, 所以也不需要再寫一遍HttpResponse了

redirect 跳轉函數

當會員註冊完成後, 我們就需要自動跳轉到會員中心頁或者首頁, 這時就得使用redirect函數來實現了
redirect(to, permanent=False, *args, **kwargs)

to: 要跳轉的地址,
permanent: 是否永久跳轉, 說白了就是301/302代碼的區別, 不動301,302自行百度。

from django.shortcuts import redirect
def my_view(request):
    ...
    return redirect(‘/some/url/‘)

reverse Url路由轉url函數

redirect完成url跳轉時, 萬一我定義的url都變了, 覺得以前定義的url太醜了, 太長了, 老板不喜歡了, 那不坑爹了麽?那我不得滿項目找url, 挨個改阿?
其實django已經想到這點了, 還記得我們在定義url路由時的name參數麽?
通過reverse函數, 就可以將urls.py中定義的url路由轉換為url了

reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
viewname: url路由的名稱
urlconf: url路由的模塊名, 默認是根模塊, 也就是咱們的cms文件中的urls.py
args: 要傳遞給url路由的參數

視圖中的Request和Response對象

一般發生請求後有兩種資源, 一種是請求的資源,是瀏覽器發送給服務器的資源, 包括請求的url, 頭, 傳遞的參數, cookie什麽的。
還有一種是返回的資源, 就是服務器發送給瀏覽器的資源。

HttpRequest對象

常用的屬性如下

屬性 說明
scheme http 或 https
body 請求的主體
path 請求的路徑 account/register/
path_info 請求的路徑
method 請求方法GET,POST
encoding 編碼類型
content_type header頭 的Content-Type
COOKIES cookie信息
FILES 表單的file字段上傳的文件信息
META header頭信息
session 保存session信息, dict結構

常用的方法

方法 說明
get_host() 127.0.0.1:8000
get_port() 請求的端口
get_full_path() 請求的全路徑
is_ajax() 是否ajax請求

HttpResponse對象

常用的屬性

屬性 說明
content 請求返回的資源內容
charset 編碼
status_code 返回的http狀態碼
JsonResponse對象

JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs)

data: 要返回的json數據, 是dict結構
encoder: 數據的轉碼類, 一般不需要更改
json_dumps_params: json_dumps函數

針對我們的項目, 就可以在cms/utils.py(沒有就創建)文件中定義一個通用的返回jsonResponse的函數,

from django.http import JsonResponse

def return_json(code = 0, message = ‘success‘, data = [], url=‘‘):
    return JsonResponse({
        ‘code‘: code,
        ‘url‘: url,
        ‘message‘: message,
    })

模板層說明

模板文件路徑

默認模板文件路徑會在模塊名/templates中, 但是在一般的項目開發中, 都會把所有的模板放在一起, 所以我們需要重新定義模板的路徑

# cms/settings.py
TEMPLATES = [
    {
        ‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘,
        ‘DIRS‘: [
            # 將templates目錄放在根目錄
            os.path.join(BASE_DIR, ‘templates‘),
        ],
        ‘APP_DIRS‘: True,
        ‘OPTIONS‘: {
            ‘context_processors‘: [
                ‘django.template.context_processors.debug‘,
                ‘django.template.context_processors.request‘,
                ‘django.contrib.auth.context_processors.auth‘,
                ‘django.contrib.messages.context_processors.messages‘,
            ],
        },
    },
]

在settings.py 中TEMPLATES.DIRS中增加os.path.join(BASE_DIR, ‘templates‘), 模板文件的目錄就變為了cms/templates

靜態資源文件路徑和訪問url修改

靜態文件路徑同模板一樣, 我們也需要修改到根目錄下

# cms/settings.py
STATIC_URL = ‘/static/‘
STATICFILES_DIRS = (‘static‘, )

模板常用標簽說明

一般模板的頂部、底部等很多地方都是一樣的, 所以我們可以定義一個布局html頁面, 將這些一樣的地方提取出來放在一起

# templates/layout.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>{% block title %} {% endblock %}</title>
    <link rel="stylesheet" href="{% static ‘css/bootstrap.min.css‘%}">
</head>

<body>
    {% block body %} {% endblock %}
</body>
<script src="{% static ‘js/jquery.min.js‘ %}"></script>
<script src="{% static ‘js/bootstrap.min.js‘ %}"></script>
<script src="{% static ‘js/layer/layer.js‘ %}"></script>
<script src="{% static ‘js/utils.js‘ %}"></script>
</html>

load static 這個標簽是指加載static模塊, 只有加載了後, 才可以使用{% static %}來讀取靜態資源文件
block endblock 定義了不同的塊, 並且為每個塊進行命名
這樣假設我定義了一個會員註冊頁

# templates/account/register.html
{% extends ‘layout.html‘ %}
{% block title %} 註冊 {% endblock %}

那麽, layout.html中的{% block title %} {% endblock %}就會被替換成"註冊"

extends 標簽, 指定的就是加載layout.html這個布局頁面

定義註冊會員的表單

我們先在account/forms.py中定義表單RegisterForm, 因為之前已經定義了一個AccountForm, 所以我們這個表單可以直接繼承AccountForm

class RegisterForm(AccountForm):
    # 設置場景是新增用戶
    scene = ‘insert‘
    class Meta(AccountForm.Meta):
        # 使用自定義的Form, 就必須指定fields or exclude屬性, 否則報錯
        # 註冊的時候我們不需要設置status, 字段, 所以排除掉。
        fields = (‘account‘, ‘password‘, ‘email‘, ‘phone‘)

註冊的時候, 一般需要輸入重復密碼, 所以我們多定義一個rep_password字段

class RegisterForm(AccountForm):
    ... 忽略代碼
     rep_password = forms.CharField(
        label=‘重復密碼‘,
        required=True,
        error_messages={‘required‘: ‘請再次輸入密碼‘},
        widget=forms.PasswordInput())

    def clean_rep_password(self):
        # 驗證兩次輸入的密碼是否一致
        # 因為在clean_password方法中, 已經加密了cleaned_data[‘password‘], 所以這裏只能取data[‘password‘]
        if self.data[‘password‘] != self.cleaned_data[‘rep_password‘]:
            raise ValidationError(‘兩次輸入的密碼不一致‘)

        return self.cleaned_data[‘rep_password‘]

定義視圖

在視圖中, 如果是GET請求, 我們則渲染表單, 如果是POST請求, 我們就執行註冊用戶

GET 請求的代碼

from django.shortcuts import render
from .forms import RegisterForm

def register(request):
    form = RegisterForm()
        return render(request, ‘account/register.html‘, {‘form‘: form})

編寫模板代碼

我使用的是bootstrap前端框架, 大家可以下載了放在static文件夾中, 修正layout.html中的路徑

首先我們先將layout.html布局模板加載進來

# templates/account/register.html
{% extends ‘layout.html‘ %}
{% block title %} 註冊 {% endblock %}

然後在block body部分, 寫入我們要渲染的表單

{% block body %}
<div class="container">
    <div class="row" style="width:500px">
        <form action="{% url ‘account-register‘%}" method="post" onsubmit="return post(this)">
            {% csrf_token %}
            <div class="form-group">
                <label for="{{ form.account.id_for_label}}">{{ form.account.label}}</label> {{ form.account}}
            </div>
            <div class="form-group">
                <label for="{{ form.password.id_for_label}}">{{ form.password.label}}</label> {{ form.password}}
            </div>
            <div class="form-group">
                <label for="{{ form.rep_password.id_for_label}}">{{ form.rep_password.label}}</label> {{ form.rep_password}}
            </div>
            <div class="form-group">
                <label for="{{ form.email.id_for_label}}">{{ form.email.label}}</label> {{ form.email}}
            </div>
            <div class="form-group">
                <label for="{{ form.phone.id_for_label}}">{{ form.phone.label}}</label> {{ form.phone}}
            </div>
            <input type="submit" value="提交" class="btn btn-success">
        </form>
    </div>
</div>
{% endblock %}

很多地方基本都是一樣的, {{ form.}} 中的form就是我們在view中傳過來的form表單類
form.account_id_for_label: 就是input的類
{{ form.account.label}}: 是顯示的表單字段的名稱
{{ form.account}}: 會直接生成一段input的表單字段代碼。

打開瀏覽器, 我們可以看一下效果
技術分享圖片

看起來樣式還不錯
現在, 我們就可以點擊提交嘗試一下了

五 【用django2.0來開發】實現會員註冊功能