Py学习  »  Django

Django2 Web实战02-用户注册登录退出

天星技术团队 • 5 年前 • 689 次点击  
阅读 33

Django2 Web实战02-用户注册登录退出

作者:Hubery

接上文:Django2 Web实战01-启动项目-model 扩展

上一节中,我们创建了工程,且创建了core应用以及core的相关models(Movie,Person)。 接下来我们在这基础上继续完善:

  • 用户注册/登陆/登出

1. 创建user应用

这里,创建一个新的Django app:user,将其注册到工程里,用来管理用户。 我们尽量那个让user app复用。

1.1 创建一个Django的app

命令行创建user

cd MyMovie
python manage.py startapp user
复制代码

注册到Django工程里 MyMovie/settings.py

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模型。

1.2 创建一个注册视图

创建视图之前,先创建一个自定义的表单: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.py

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方法。

  • template_name = 'user/register.html',这是将要创建的模版。它的context与之前见过的稍微有些不同;它没有objectobject_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中用户输入的数据来创建用户,并保存到数据库中,同时渲染出创建成功的模版。

1.3 创建注册视图对应的模版

写模版前我们要知道,Django没有提供

或者<button type='submit'>之类的tag,只是提供了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个基本的部分:

  • <label>tag 显示字段名字
  • <ul class='errorlist'>tag 显示用户之前提交的错误信息,只有出错的时候才会显示
  • <input>或者<select>tag 接收用户输入
  • <span class='helptext'>tag 显示帮助信息

Form附带了以下三个工具方法来渲染form:

  • as_table(),每个字段都包含在<tr>tag中,标签在<th>tag中,控件包含在<td>tag中。没有提供<table>tag。
  • as_ul,整个字段(label和帮助widget)都包含在<li>tag中。没有提供<ul>tag。
  • as_p, 整个字段包含在<p>tag中。

不提供<table>和<ul> tag的form,不提供<form> tag,以便在必要的时候输出多个form。

上面代码中,我们用了as_p()方法,因为我们不需要很细粒度的布局控制,稍微显示下就好。 第一次在模版中使用csrf_token的tag。CSRF是web应用的常见漏洞,后续会提到。Django会自动检查所有POST/GET请求是否具有有效的csrfmiddlewaretokenheader。如果请求中缺失这些信息,则该请求不会到达视图,返回一个403 Forbidden

已经有了模版,接下来在URLConf中添加一个path()对象来配置我们的视图。

1.4 给RegisterView添加一个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。

1.5 登陆登出

Django的auth应用提供了登陆/登出视图。集成需要两步:

  • 将登陆/登出视图注册到user的URLConf中;
  • 给登陆/登出视图添加模版

1.5.1 更新user的URLConf

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 *; 不要前缀,一键导入,不建议这么做,可能会有问题,最好是用到哪个注册哪个。

1.5.2 创建LoginView模版

创建一个模版 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/
复制代码

显示截图:

登陆页面

嗯,那么问题来了,如果登陆成功了,跳哪儿去?

1.5.3 登陆成功的跳转

RegisterView中,我们可以指定登陆成功之后往哪儿跳。LoginView类可以通过以下几个步骤来决定往哪儿跳:

  • 如果URL有效,用POST的参数next,指向托管此应用的server。path()的名字不可用。
  • 如果URL有效,用GET的参数next,执行托管此应用的server。path()的名字不可用。
  • LOGIN_REFIRECT_URL有个默认设置'/accounts/profile/'。path()的名字可用。

我们这里,登陆成功之后都跳转到movie列表,那么我们更新MyMovie/settings.py文件添加一个LOGIN_REFIRECT_URL设置:

LOGIN_REDIRECT_URL = 'core:MovieList'
复制代码

配置好登陆成功后到跳转页,看截图:

登陆成功跳转列表

然而,有这么种情况,如果想让用户跳转到指定的页面,我们可以用next参数来指定跳转页。如用户在登录之前要尝试执行某些操作,我们会将登陆前所在的页面作为一个next参数传递给LoginView,以便登陆成功之后再重定向回来。 即:访问设备列表->跳转到登陆页->登陆成功后->重定向回设备列表。

1.5.4 创建一个登出模版

这个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步,一旦找到文件就会停止解析,如下:

  • Django迭代settings.TEMPLATES数组下的DIRS目录;
  • 如果APP_DIRSTrue,那么Django会迭代INSTALLED_APPS目录,直到找到匹配的为止。如果INSTALLED_APPS列表的注册应用admin在user之前,那么admin会优先被匹配到;如果user在admin之前,那么user优先被匹配。
  • 如果没找到,会抛出一个异常:TemplateDoesNotExist

这就是为啥我们将user放到admin之前,且添加了注释,以便警告后续的接手人员不要改变注册的前后顺序。

1.6 user小结

我们创建了user应用,来封装用户管理。在user应用中,我们使用了不少Django内置应用auth提供的功能,包括:UserCreationFormLoginViewLogoutView等。我们也学习了下如何创建新的Django提供的视图,用CreateViewUserCreationForm组合起来创建一个RegisterView视图。

既然有了用户,那么就可以让他们来给movies进行投票了。

天星技术团QQ:557247785

欢迎来扰


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/ysZkdd71XC
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/24077
 
689 次点击