您好,登錄后才能下訂單哦!
上一節我們完成了會員功能的后臺管理, 這一節我們需要完成會員注冊功能, 涉及到以下幾個模塊
項目地址:https://gitee.com/ccnv07/django_example
django是通過項目的urls.py文件來定義網站的url路由, 在我們的項目中是cms/urls.py文件
django的基本訪問流程
打開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/
這種路由是固定訪問的url, 不會發生變化, 比如關于我的訪問頁面.
urlpatterns = [
path('about/', views.about),
]
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
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
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文件中定義了。
創建account/urls.py文件
# account/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('register/', views.register, name='account-register')
]
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對象
但是如果把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(to, permanent=False, *args, **kwargs)
to
: 要跳轉的地址, permanent
: 是否永久跳轉, 說白了就是301/302代碼的區別, 不動301,302自行百度。
from django.shortcuts import redirect
def my_view(request):
...
return redirect('/some/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.pyargs
: 要傳遞給url路由的參數
一般發生請求后有兩種資源, 一種是請求的資源,是瀏覽器發送給服務器的資源, 包括請求的url, 頭, 傳遞的參數, cookie什么的。
還有一種是返回的資源, 就是服務器發送給瀏覽器的資源。
常用的屬性如下
屬性 | 說明 |
---|---|
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請求 |
常用的屬性
屬性 | 說明 |
---|---|
content | 請求返回的資源內容 |
charset | 編碼 |
status_code | 返回的http狀態碼 |
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
靜態文件路徑同模板一樣, 我們也需要修改到根目錄下
# 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" >
<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的表單字段代碼。
打開瀏覽器, 我們可以看一下效果
看起來樣式還不錯
現在, 我們就可以點擊提交嘗試一下了
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。