django 实战(13): 用户登录、注册、登出

前面在第7节讲解利用管理后台创建基础数据时,讲到了用户登录。这里我们自己定义登录和注册页面。自定义登录、注册函数。

1 实现用户登录

1.1 在users/forms.py定义表单LoginForm

from django import forms

from .models import User

from django.core.exceptions import ValidationError

# Login表单

class LoginForm(forms.Form):

  username = forms.fields.CharField(

    label='用户名',

    required=True,

    min_length=3,

    max_length=50,

    error_messages={

      "required":"用户名不可以为空",

      "min_length":"用户名不能低于3",

      "max_length":"用户名不能超过50"

    }

  )

  password = forms.fields.CharField(

    label='密码',

    required=True,

    widget=forms.PasswordInput(),

    error_messages={

      "required":"密码不可以空",

    }

  )

  remember = forms.fields.BooleanField(

    required=False,

    label='使用系统默认的session过期时间'

  )

1.2 在views.py中定义登入函数loginView()

from django.shortcuts import render

# Create your views here.

from django.http import JsonResponse

from .forms import RegisterForm,LoginForm

from django.contrib.auth import authenticate,login

# 导入获取自定义User对象的方法

from django.contrib.auth import get_user_model

User = get_user_model()     # 获取自定义User模型

# 登录视图名称不能起成login与自带login函数重名

def loginView(request):

  #初始化返回信息

  context ={}

  if request.method == "GET":

    context['code'] =''

    context['message'] = '不应该用GET方法,应该用POST方法'

    context['error'] = ''

  else:

    form = LoginForm(request.POST)

    if form.is_valid():

      username = form.cleaned_data.get("username")

      password = form.cleaned_data.get("password")

      '''

      因为前端checkbox若选择,则传上来的'on',所以要进行处

      '''

      if request.POST.get("remember")=='on':

        remember = 1

      else:

        remember = 0

      # 使用authenticate进行登录验证验证成功会返回一个user对象失败则返回None

      # 使用authenticate验证时如果is_activeFalse也会返回None导致无法判断激活状态

      # 此时可以在seetings中配置

      # AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']

      user = authenticate(request,username=username,password=password)

      # 如果验证成功且用户已激活执行下面代码

      if user and user.is_active:

        # 使用自带的login函数进行登录会自动添加session信息

        login(request,user)

        # 自定义sessionlogin函数添加的session不满足时可以增加自定义的session信息

        request.session["username"] = username

        if remember:

          request.session.set_expiry(None) # 设置session过期时间None表示使用系统默认的过期时间

        else:

          request.session.set_expiry(0) # 0代表关闭浏览器session失效

        context['code'] = 200

        context['message'] = "验证通过"

        context['error'] = ''

        return JsonResponse({"code": 200,"message":"验证通过","data":{ "error":""}})

      elif user and not user.is_active:

        context['code'] = 400

        context['message'] = "用户未激活"

        context['error'] = '该用户还没有激活,请联系系统管理员激活'

      else:

        context['code'] = 400

        context['message'] = "验证失败"

        context['error'] = '用户名或密码错误'

    else:

      context['code'] = 400

      context['message'] = "用户名或密码格式错误"

      context['error'] = '用户名或密码错误'

  context['form'] = LoginForm()

  print(LoginForm())

  return render(request,'login.html',context)

 1.3 模板文件

1.3.1 在users/templates/users中定义模板文件base.html

在templates/users/目录下新建应用的父模板文件base.html,在中引入bootstrap、jquery、Font Awesome。

DOCTYPE html>

<html>

<head>

  <meta charset="UTF-8">

 

  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

 

  <link rel="stylesheet" href="/static/plugins/bootstrap-4.5.3-dist/css/bootstrap.min.css">

 

  <link rel="stylesheet" href="/static/plugins/bootstrap-4.5.3-dist/fontawesome-free-6.4.0-web/css/all.css">

 

  <script type="text/javascript" src="/static/js/jquery-3.5.1/jquery-3.5.1.min.js">script>

 

  <script src="/static/plugins/bootstrap-4.5.3-dist/js/bootstrap.bundle.min.js">script>

 

 

  <script src="/static/plugins/bootstrap-4.5.3-dist/js/bootstrap.min.js">script>

 

  <script src="/static/js/utility.js">script>

  <title>讲座签到系统title>

head>

<body>

<div class="container-liquid">

  {# 子模板要替换的主体块 名为mainBody #}

  {% block mainBody %}  

  {% endblock %}

div>

body>

html>

1.3.2 在users/templates中定义模板文件login.html

模板中表单的各输入项,是参照LoginForm表单的输入而来的(具体是复制在视图函数loginView()中,向控制台输出了print(LoginForm())的结果)

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

{% block mainBody %}

<div class="container">

  <script>

    console.log('message ='+"{{message}}")

    console.log('error ='+"{{error}}")

  script>

  <div style="width: 600px;height: 50px;">div>

  <div class='text-white text-center bg-info' style="width: 600px;height: 10px;">div>

  <div class='text-white text-center bg-info' style="width: 600px;height: 40px;">

    <h4>登录界面h4>

  div>

  <div class='bg-light' style="width: 600px; height: 30px ;">div>

  <div class='bg-light' style="width: 600px; ">

    <div  class="container" style="width: 400px; height: 280px;" >

    <form action={% url "login-url" %} method="post">

      {% csrf_token %}

      <h5>

        <div class="form-group">

          <label for="id_username">用户名:label>

          <input type="text" class="form-control" name="username" maxlength="50" minlength="3" required id="id_username">

        div>

        <div class="form-group">

          <label for="id_password">密码:label>

          <input type="password" class="form-control" name="password" required id="id_password">

        div>

        <div class="form-group">

          <label for="id_remember">使用系统默认的session过期时间:label>

          <input type="checkbox"  name="remember" id="id_remember">

        div>

        <input type="submit" class="btn btn-info btn-lg" value="登录">

                  

        <a href="#" class="btn btn-info btn-lg" role="button">注册a>

      h5>

    form>

  div>

   

  {% if code == 400 %}

    <div  class="container" style="width: 400px;" id="warning">

      <div class="alert alert-warning">

        <p><strong>{{message}}!strong>p>

      div>

    div>

   

    <script>

      function remove() {

        document.getElementById('warning').remove()

      }

      setTimeout(remove, 5000)

    script>

  {% endif %}

div>

div>

{% endblock %}

 1.4 在users/urls.py设置子路由login

        from django.urls import path,re_path

        from . import views as view

        # 子路由列表

        urlpatterns = [

          path('query/', view.query,  name='query-url'),  # 分页查询

          re_path(r'^query/(?P\d+)/(?P\d+)/$',view.query),  #传值路由

          path('add/',   view.add,    name='add-url'),     # 新增

          path('update/',view.update, name='update-url'),  # 修改

          path('delete/',view.delete, name='delete-url'),  # 删除

          path('login/',view.loginView, name='login-url'),  # 登录

        ]

 1.5 访问http://127.0.0.1:8000/users/login/

django 实战(13): 用户登录、注册、登出_第1张图片

 2 用户注册

2.1 在users/forms.py定义表单RegisterForm

# 注册表单

class RegisterForm(forms.Form):

  username = forms.fields.CharField(

    required=True,

    min_length=3,

    max_length=50,

    error_messages={

      "required":"用户名不可以为空!",

      "min_length":"用户名不能低于3位!",

      "max_length":"用户名不能超过50位!"

    }

  )

  password1 = forms.fields.CharField(

    required=True,

    widget=forms.PasswordInput(),

    min_length=6,

    max_length=50,

    error_messages={

      "required":"密码不可以空",

      "min_length": "密码不能低于6位!",

      "max_length": "密码不能超过50位!"

    }

  )

  password2 = forms.fields.CharField(

    required=False,

    widget=forms.PasswordInput(),

    )

  email = forms.fields.EmailField(

    required=True,

    error_messages={

    "required":"邮箱不可以为空!"

    },

  )

  def clean_password2(self):

    if not self.errors.get("password1"):

      if self.cleaned_data["password2"] != self.cleaned_data["password1"]:

        raise ValidationError("您输入的密码不一致,请重新输入!")

    return self.cleaned_data

 2.2 在users/views.py中定义登入函数register()

# 用户注册

def register(request):

  #初始化返回结果

  context ={}

  context['form'] = RegisterForm()

  context['code'] = 400

  context['message'] = '注册失败'

  context['username_err'] = ""

  context['password1_err'] = ""

  context['password2_err'] = ""

  context['email_err'] = ""

  print(RegisterForm())

  if request.method == "GET":

    context['code'] = 0

    context['message'] = '不应该用GET方法,应该用POST方法'

    return render(request,"register.html",context)

  else:

    form = RegisterForm(request.POST)

    if form.is_valid():

      username = form.cleaned_data["username"]

      password = form.cleaned_data["password1"]

      email = form.cleaned_data["email"]

      username_exists = User.objects.filter(username=username).exists()

      # 如果用户名已经存在

      if username_exists:

        context['username'] = "您输入的用户名已存在!"

        return render(request,"register.html",context)

      else:

        # 如果邮箱名已经存在

        email_exists = User.objects.filter(email=email).exists()

        if email_exists:

          context['email_err'] = "您输入的邮箱已存在!"

          return render(request,"register.html",context)

        #注册通过返回login页面

        else:

          print("注册通过")

          User.objects.create_user(username=username,password=password,email=email)

          context['code'] = 200

          context['message'] = '注册通过'

          return redirect('/users/login')

    else:

      context['username_err'] = form.errors.get("username")

      context['password1_err'] = form.errors.get("password1")

      context['password2_err'] = form.errors.get("password2")

      context['email_err'] = form.errors.get("email")

      return render(request,"register.html",context)

  2.3 在users/templates中定义模板文件register.html

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

{% block mainBody %}

<div class="container">

  <div style="width: 600px;height: 50px;">div>

  <div class='text-white text-center bg-info' style="width: 600px;height: 10px;">div>

  <div class='text-white text-center bg-info' style="width: 600px;height: 40px;">

    <h4>注册界面h4>

  div>

  <div class='bg-light' style="width: 600px; height: 30px ;">div>

  <div class='bg-light' style="width: 600px; ">

    <div  class="container" style="width: 400px; height: 410px;" >

      <form action={% url "register-url" %} method="post">

        {% csrf_token %}

        <h5>

          <div class="form-group">

            <label for="id_username">用户名:label>

            <input type="text" class="form-control" name="username" maxlength="50" minlength="3" required id="id_username">

          div>

          <div class="form-group">

            <label for="id_password">电子邮箱:label>

            <input type="email" class="form-control" name="email" required id="id_email">

          div>

          <div class="form-group">

            <label for="id_password1">收入密码:label>

            <input type="password" class="form-control" name="password1" maxlength="50" minlength="6" required id="id_password1">

          div>

          <div class="form-group">

            <label for="id_password2">再次输入密码:label>

            <input type="password" class="form-control" name="password2" required id="id_password2">

          div>

          <input type="submit" class="btn btn-info btn-lg" value="注册">

                    

          <a href={% url "login-url" %} class="btn btn-info btn-lg" role="button">返回a>

        h5>

      form>

    div>

   

    {% if code == 400 %}

      <div  class="container" style="width: 400px;" id="warning">

        <div class="alert alert-warning">

          <p><strong>{{message}}!strong>p>

          <script>

            /* 后端的空字符串到前端来变成了None 处理*/

            if ("{{username_err}}"=='None'){"{{username_err}}"=''}

            if ("{{password1_err}}"=='None'){"{{password1_err}}"=''}

            if ("{{password2_err}}"=='None'){"{{password2_err}}"=''}

            if ("{{email_err}}"=='None'){"{{email_err}}"=''}

          script>

          <p>原因:{{username_err}}{{password1_err}}{{password2_err}}{{email_err}}p>

        div>

      div>

     

      <script>

        function remove() {

          document.getElementById('warning').remove()

        }

        setTimeout(remove, 5000)

      script>

    {% endif %}

  div>

div>

div>

{% endblock %}

2.4 在users/urls.py设置子路由login

        from django.urls import path,re_path

        from . import views as view

        # 子路由列表

        urlpatterns = [

          path('query/', view.query,  name='query-url'),  # 分页查询

          re_path(r'^query/(?P\d+)/(?P\d+)/$',view.query),  #传值路由

          path('add/',   view.add,    name='add-url'),     # 新增

          path('update/',view.update, name='update-url'),  # 修改

          path('delete/',view.delete, name='delete-url'),  # 删除

          path('login/',view.loginView, name='login-url'),  # 登录

          path('register/',view.register, name='register-url'),  # 注册

        ]

 2.5 访问http://127.0.0.1:8000/users/register/

django 实战(13): 用户登录、注册、登出_第2张图片

 

你可能感兴趣的:(django,数据库,sqlite)