做者:Hubery 时间:2018.9.14html
接上文:Django2 Web实战01-启动项目-model 扩展java
上一节中,咱们建立了工程,且建立了core应用以及core的相关models(Movie,Person)。 接下来咱们在这基础上继续完善:python
这里,建立一个新的Django app:user,将其注册到工程里,用来管理用户。 咱们尽可能那个让user app复用。web
命令行建立user数据库
cd MyMovie
python manage.py startapp user
复制代码
注册到Django工程里 MyMovie/settings.pydjango
INSTALLED_APPS = [
'user', # 必须在admin以前
'core',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
复制代码
注: 将咱们的app放到Django自带的app以前注册,是个好习惯。 Django的内建app:auth
,为咱们提供了一个可用的user
模型。数组
建立视图以前,先建立一个自定义的表单:UserForm,包含几个注册内容:username/first_name/last_name/password/email,这应该算是一个用户最基本的信息了; 好 user/forms.py,若是没有forms.py文件,就地建立:浏览器
from django import forms
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput({
'class': 'form-control',
'placeholder': '请输入用户名'}))
first_name = forms.CharField(widget=forms.TextInput({
'class': 'form-control',
'placeholder': '请输入名字'}))
last_name = forms.CharField(widget=forms.TextInput({
'class': 'form-control',
'placeholder': '请输入姓氏'}))
password = forms.CharField(widget=forms.PasswordInput({
'class': 'form-control',
'placeholder': '请输入密码'}))
email = forms.CharField(widget=forms.TextInput({
'class': 'form-control',
'placeholder': '请输入邮箱'}))
class Meta:
model = User
fields = ('username',
'first_name',
'last_name',
'email',
'password')
复制代码
RegisterView类可让用户在咱们的网站上注册。重写get post函数,处理注册成功/失败的状况。 user/views.pybash
from django.contrib.auth.models import User
from django.shortcuts import render
from django.views.generic import View
from user.forms import UserForm
# 注册视图
class RegisterView(View):
form_class = UserForm # 上文自定义的表单
template_name = 'user/register.html'
# 显示空表单
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
# 处理POST表单数据
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
first_name=form.cleaned_data['first_name'],
last_name=form.cleaned_data['last_name'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password'],
)
# 保存到数据库中
user.save()
# 注册成功以后 跳转到成功页面
return render(request, 'user/register_success.html', {'form': form})
return render(request, self.template_name, {'form': form})
复制代码
RegisterView继承了View
,须要重写GET/POST方法。session
template_name = 'user/register.html',这是将要建立的模版。它的context与以前见过的稍微有些不一样;它没有object
或object_list
变量,但有个form
变量,这个变量是一个类实例,咱们在form_class
属性中设置的。
form_class = UserForm
,这就是View要用的form
类。简单的模型能够直接设置model = MyModel
,但一个user模型比较复杂,不能直接这么设置。这个问题能够后续详述。
若是View接收到一个GET请求,它会给form渲染一个空模版。
若是View接收到一个POST请求,一样会经过self.form_class(request.POST)
来建立form实例。若是该form有效:form.is_valid(),则根据form中用户输入的数据来建立用户,并保存到数据库中,同时渲染出建立成功的模版。
写模版前咱们要知道,Django没有提供<form>或者<button type='submit'>之类的tag,只是提供了form的内容。这让咱们能够在同一个<form>中包含多个Django表单。 添加一个模版:必须遵循路径和命名规范,以前讲过。 user/templates/user/register.html
{% extends 'base.html' %}
{% block main %}
<h1>注册MyMovie</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" >
注册
</button>
</form>
{% endblock %}
复制代码
user/templates/user/register_success.html
{% extends 'base.html' %}
{% block main %}
<div class='create-account-msg-container'>
<div class='circle'>
<i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
</div>
<h3>帐户已成功注册!</h3>
<a href="{% url 'user:login' %}">点击登录</a>
</div>
{% endblock %}
复制代码
这两个模版与以前的模版同样,继承base.html,将代码写在已经存在的block中。 当一个模版渲染出来,将被渲染成两部分,第一部分是可选的tag,<ul class='errorlist'>用来生成错误信息,而后每一个字段都被渲染成4个基本的部分:
Form
附带了如下三个工具方法来渲染form:
不提供<table>和<ul> tag的form,不提供<form> tag,以便在必要的时候输出多个form。
上面代码中,咱们用了as_p()方法,由于咱们不须要很细粒度的布局控制,稍微显示下就好。 第一次在模版中使用csrf_token
的tag。CSRF是web应用的常见漏洞,后续会提到。Django会自动检查全部POST/GET请求
是否具备有效的csrfmiddlewaretoken
和header
。若是请求中缺失这些信息,则该请求不会到达视图,返回一个403 Forbidden
。
已经有了模版,接下来在URLConf
中添加一个path()对象
来配置咱们的视图。
user应用下没有urls.py文件,要手动建立user/urls.py
from django.urls import path
from user import views
app_name = 'user'
urlpatterns = [
path('register/', views.RegisterView.as_view(), name='register'),
]
复制代码
而后在根URLConf中包含这个URLConf: MyMovie/urls.py
from django.contrib import admin
from django.urls import path, include
import core.urls
import user.urls
urlpatterns = [
path('admin/', admin.site.urls),
path('user/', include(user.urls, namespace='user')),
path('', include(core.urls, namespace='core')),
]
复制代码
写完RegisterView,模版,以及将RegisterView注册到工程后,浏览器:
http://127.0.0.1:8000/user/register/
复制代码
用户注册UI及数据库写入见截图:
注:因为URLConf只会在找到第一个匹配path以前进行搜索,匹配成功以后的URL再也不处理。因此咱们尽可能把没有前缀或者通用的URLConfs的path放到最后,这样就不会意外阻止其余的视图的加载。若是把没有前缀的path放到最前面,可能会致使意外状况出现,不执行后续配置的path。
Django的auth
应用提供了登录/登出视图
。集成须要两步:
Django的auth
应用提供了不少视图来简化用户管理和验证,包括登录登出,更改密码,找回密码等。一个功能齐全的产品的用户模块,至少提供这3个功能。这里呢,咱们简化一下,只用到登录/登出。
更新下user/urls.py
来使用auth
应用的登录/登出
功能:
from django.urls import path
from user import views
from django.contrib.auth import views as auth_views
app_name = 'user'
urlpatterns = [
path('register/', views.RegisterView.as_view(), name='register'),
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]
复制代码
注: 若是你就要想提供auth应用提供的全部视图,那你能够这么配置URLConf:
from django.contrib.auth import urls
app_name = 'user'
urlpatterns = [
path('', include(urls)),
]
复制代码
相似于java的导包, import *;
不要前缀,一键导入,不建议这么作,可能会有问题,最好是用到哪一个注册哪一个。
建立一个模版 user/templates/registration/login.html
{% extends 'base.html' %}
{% block title %}
登录 - {{ block.super }}
{% endblock %}
{% block main %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary">
登录
</button>
</form>
{% endblock %}
复制代码
这个代码是否是和user/register.html很像? 对比下看看?
{% extends 'base.html' %}
{% block main %}
<h1>注册MyMovie</h1>
<form method="post">
{{ form.as_p }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">
注册
</button>
</form>
{% endblock %}
复制代码
浏览器中输入:
http://127.0.0.1:8000/user/login/
复制代码
显示截图:
嗯,那么问题来了,若是登录成功了,跳哪儿去?
RegisterView中,咱们能够指定登录成功以后往哪儿跳。LoginView类能够经过如下几个步骤来决定往哪儿跳:
咱们这里,登录成功以后都跳转到movie列表,那么咱们更新MyMovie/settings.py文件添加一个LOGIN_REFIRECT_URL设置:
LOGIN_REDIRECT_URL = 'core:MovieList'
复制代码
配置好登录成功后到跳转页,看截图:
然而,有这么种状况,若是想让用户跳转到指定的页面,咱们能够用next
参数来指定跳转页。如用户在登陆以前要尝试执行某些操做,咱们会将登录前所在的页面做为一个next
参数传递给LoginView,以便登录成功以后再重定向回来。 即:访问设备列表->跳转到登录页->登录成功后->重定向回设备列表。
这个LogoutView比较直接。当收到GET请求,会推出用户登录而后尝试渲染registration/logged_out.html。
{% extends 'base.html'%}
{% block title %}
登出
{% endblock %}
{% block main %}
<h1>登出</h1>
<p>自定义登出模版</p>
{% endblock %}
复制代码
GET请求能修改用户的状态,这很不寻常,因此值得记住这个视图LogoutView的不一样之处。 LogoutView还有另一个不寻常的地方,若是你没提供registration/logged_out.html模版,同时你在settings.py中已经注册了admin应用,那么Django可能会使用admin应用中自带的模版。 见截图:
Django将模版名称解析为文件的方式,要经历3步,一旦找到文件就会中止解析,以下:
settings.TEMPLATES数组
下的DIRS
目录;APP_DIRS
是True
,那么Django会迭代INSTALLED_APPS
目录,直到找到匹配的为止。若是INSTALLED_APPS列表的注册应用admin在user以前,那么admin会优先被匹配到;若是user在admin以前,那么user优先被匹配。TemplateDoesNotExist
。这就是为啥咱们将user放到admin以前,且添加了注释,以便警告后续的接手人员不要改变注册的先后顺序。
咱们建立了user应用,来封装用户管理。在user应用中,咱们使用了很多Django内置应用auth
提供的功能,包括:UserCreationForm
,LoginView
,LogoutView
等。咱们也学习了下如何建立新的Django提供的视图,用CreateView
和UserCreationForm
组合起来建立一个RegisterView
视图。
既然有了用户,那么就可让他们来给movies进行投票了。
天星技术团QQ:557247785
。