基于Django3.0 实现注册、登录

2024-03-23 07:40
文章标签 实现 登录 注册 django3.0

本文主要是介绍基于Django3.0 实现注册、登录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Django3.0 实现注册和登录功能

2020-6-1

Django3.0在2.0的基础上完善了websock的功能,因为想在我现在做的项目上加上及时通讯的功能,使用了Django3.0版本,本教程讲解如何实现网页登录功能。

源码:请访问Github
在这里插入图片描述

 

1、 创建APP

对于创建项目和虚拟环境我就不赘述了,直接从APP开始。为了代码管理更方便我把所有的APP放到APPS文件夹内,此时的目录结构如图

在这里插入图片描述
统一有关用户操作的功能都放到user的app中。
在setting.py中注册user APP
在这里插入图片描述
为了方便管理我在本项目中使用了二级域名。所以在mysite的url中还需要配置二级域名的url。所以需要在user APP中新增一个名为urls的python文件。并且在mysite的urls中添加进去。在这里插入图片描述
此时基础工作已经完成。

 

2、 需求分析&数据库设计

为了满足我们的需求,对页面进行分析。设计数据库。
注册功能中,通过邮箱注册,服务器发送注册链接到注册邮箱,用户点击链接完成注册。
所以需要的字段有:
用户名
用户密码
验证链接码等。django自带的库中有user相关的库,进行重写:

 
models.py

import datetimefrom django.db import modelsfrom django.contrib.auth.models import AbstractUser# 用户信息
class UserInformationModel(AbstractUser):nike_name = models.CharField(max_length=50, verbose_name=u"昵称", default='')birthday = models.DateField(verbose_name=u'生日', null=True, blank=True)gender = models.CharField(max_length=6, choices=(("male", u"男"), ("female", u"女")), default="female")image = models.ImageField(upload_to="image/%Y/%m", default="image/default.png", max_length=200, null=True)describe = models.CharField(max_length=500, default=' ', verbose_name=u'个性签名')class Meta:verbose_name = "用户信息"verbose_name_plural = verbose_namedef __unicode__(self):return self.username# 验证码
class EmailVerificationModel(models.Model):code = models.CharField(max_length=20, verbose_name=u'验证码')email = models.EmailField(max_length=200, verbose_name=u'邮箱')send_type = models.CharField(max_length=10, choices=(("register", u'注册'), ("forget", u'密码找回')))send_time = models.DateTimeField(default=datetime.now)class Meta:verbose_name = u'邮箱验证码'verbose_name_plural = verbose_name

需要将以上的字段保存到数据库中,所以在setting中配置数据库信息。

DATABASES = {'default': {# 数据库类型'ENGINE': 'django.db.backends.mysql',# 数据库名称'NAME': 'blog',#登录用户'USER': 'root',#登录密码'PASSWORD': '151968',# 主机'HOST': 'localhost',#端口'PORT': '3306',}
}

在数据库同步之前,因为是继承AbstractUser类,需要在setting.py文件中添加:

# 设置用户组
AUTH_USER_MODEL = "user.UserInformationModel"

否则会报错。

数据库同步:

python manage.py makemigrations
python manage.py migrate

在数据库中发现下表表示同步成功

在这里插入图片描述

3、 功能实现

使用Django自带的Form进行简单的前端验证,以减少垃圾注册,减少服务器负担。
在user文件夹中新建一个form.py

form.py:

from django import formsfrom captcha.fields import CaptchaField#用户登录
class UserLoginForm(forms.Form):Username = forms.CharField(required=True)Password = forms.CharField(required=True, min_length=6)#用户注册
class UserRegisterForm(forms.Form):# 用户名验证 字段需要与前端input的name属性保持一致Username = forms.CharField(required=True)# 密码验证 字段需要与前端input的name属性保持一致Password = forms.CharField(required=True, min_length=6)# 重复密码验证  字段需要与前端input的name属性保持一致rPassword = forms.CharField(required=True)# 验证码captcha = CaptchaField(error_messages={"Invalid": u'验证码错误'})

验证码使用第三方库captcha,pip安装后注册到setting.py中.

3.1 邮箱验证码功能实现

在user app中添加一个python package文件夹,添加Email_Send.py
此时目录结构为:
在这里插入图片描述

在Email_Send.py中编写:

from apps.user.models import EmailVerificationModelfrom random import Randomfrom django.core.mail import send_mailfrom mysite.settings import EMAIL_FROM# 获取随机字符串
def get_random_string(code_length):string = ""chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'length = len(chars) - 1random = Random()for i in range(code_length):string += chars[random.randint(0, length)]return stringdef Email_Send_Register(email,sendtype="register"):email_content = EmailVerificationModel()email_code = get_random_string(16)email_content.code = email_codeemail_content.email = emailemail_content.send_type = sendtypeemail_content.save()email_title = '用户注册'email_body = '点击此链接完成注册.http://127.0.0.1:8000/user/sign-up/activate/{0}'.format(email_code)send_key = send_mail(email_title, email_body, EMAIL_FROM, [email])def Email_Send_Forget(email,sendtype="forget"):email_content = EmailVerificationModel()email_code = get_random_string(16)email_content.code = email_codeemail_content.email = emailemail_content.send_type = sendtypeemail_content.save()email_title = '密码找回'email_body = '点击此链接密码找回.http://127.0.0.1:8000/user/forget/verification/{0}'.format(email_code)send_key = send_mail(email_title, email_body, EMAIL_FROM, [email])

同时并且在setting中添加邮箱配置:

# 邮件发送,使用第三方代理服务器发送
EMAIL_HOST = 'smtp.qq.com'EMAIL_PORT = 25# 邮件发送主机用户名
EMAIL_HOST_USER = 'XXXX@qq.com'
# SMTP代理发送密码
EMAIL_HOST_PASSWORD = ''EMAIL_USE_TLS = False# 代理服务器发送
# EMAIL_USE_SSL = True
# 邮件发送者地址
EMAIL_FROM = 'XXXX@qq.com'

因为注册页面需要使用到验证码,所以需要对验证码进行配置:

# captcha验证码
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_null',)
CAPTCHA_LENGTH = 6
# 超时(minutes)
CAPTCHA_TIMEOUT = 1

静态文件配置:

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"),
]

配置之后再同步一下数据库:

python manage.py makemigrations
python manage.py migrate

此时就可以编写视图函数了。
 

3.2、 View.py编写

views.py:

from django.shortcuts import render# emil
from apps.user.until.Email_Send import *# 加密
from django.contrib.auth.hashers import make_password
from django.contrib.auth.hashers import check_password# 查询
from django.db.models import Q
from django.contrib.auth.backends import ModelBackend# 登录
from django.contrib.auth import authenticate
from django.contrib.auth import login
from django.contrib.auth import logout# 跳转
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.shortcuts import reverse# view
from django.views.generic.base import View# from
from .form import *# model
from .models import UserInformationModel# 重写类方法根据邮箱和用户名查找
class UserVerificationView(ModelBackend):def authenticate(self, request, username=None, password=None, **kwargs):try:user_information = UserInformationModel.objects.get(Q(email=username) | Q(username=username))if check_password(password, user_information.password):return user_informationexcept Exception as err:return None# 登录
class UserLoginView(View):def get(self, request):user_login_form = UserLoginForm()return render(request, "sign-in.html", locals())def post(self, request):user_login_form = UserLoginForm(request.POST)if user_login_form.is_valid():username = request.POST.get("Username", "")password = request.POST.get("Password", "")try:user_information = authenticate(username=username, password=password)if user_information is not None:if user_information.is_active:login(request, user_information)# 定向跳转到博客主页return HttpResponseRedirect(reverse("blog-index"))else:return render(request, "sign-in.html", {"message": "该用户尚未激活!",})else:return render(request, "sign-in.html", {"message": "用户名或密码错误!",})except Exception as error:return render(request, "sign-in.html", {"message": "未知错误,请与网站管理员联系!",})# 注册
class UserRegisterView(View):def get(self, request):UserRegister = UserRegisterForm()return render(request, "sign-up.html", locals())def post(self, request):UserRegister = UserRegisterForm(request.POST)if UserRegister.is_valid():username = request.POST.get("Username", "")password = request.POST.get("Password", "")rpassword = request.POST.get("rPassword", "")if password != rpassword:return render(request, "sign-up.html", {"message": "两次密码输入不一致!","UserRegister": UserRegister,})if UserInformationModel.objects.filter(email=username):return render(request, "sign-up.html", {"message": "该邮箱已被注册!","UserRegister": UserRegister,})UserInformation = UserInformationModel()UserInformation.email = usernameUserInformation.username = usernameUserInformation.is_active = FalseUserInformation.password = make_password(password)UserInformation.save()Email_Send_Register(email=username, sendtype="register")return render(request, "user-sign-up-turn.html")else:UserRegister = UserRegisterForm()return render(request, "sign-up.html", locals())# 用户验证
class UserActivateView(View):def get(self, request, activate_code):all_records = EmailVerificationModel.objects.filter(code=activate_code)if all_records:for record in all_records:email = record.emailuser = UserInformationModel.objects.get(email=email)user.is_active = Trueuser.save()else:return render(request, 'user-sign-up-activate-fail.html')return render(request, 'user-sign-up-activate-succeed.html')

user-sign-in.html:

{% load static %}
<!DOCTYPE html>
<html>
<head><title>用 户 登 录</title><meta name="viewport" content="width=device-width, initial-scale=1"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><script type="application/x-javascript"> addEventListener("load", function () {setTimeout(hideURLbar, 0);}, false);function hideURLbar() {window.scrollTo(0, 1);} </script><link href="{% static 'login&register/css/snow.css' %}" rel="stylesheet" type="text/css" media="all"/><link href="{% static 'login&register/css/style.css' %}" rel="stylesheet" type="text/css" media="all"/><link rel="stylesheet" href="{% static 'font-awesome/css/font-awesome.css' %}"><!- Layui -><link href="{% static 'layui/css/layui.css' %}" rel="stylesheet"><!- ico -><link href="{% static "login&register/css/font-awesome.min.css" %}" rel="stylesheet" type="text/css" media="all"><!- js -><script type="text/javascript" src="{% static 'jQuery/jquery-3.3.1.js' %}"></script><script type="text/javascript" src="{% static 'jQuery/jquery-3.3.1.min.js' %}"></script><script type="text/javascript" src="{% static 'layui/layui.js' %}"></script><script type="text/javascript" src="{% static 'layui/layui.all.js' %}"></script><!-- web font --><link href="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet"><link href="//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" rel="stylesheet"><!-- //web font -->
</head>
<body>
<div class="snow-container"><div class="snow foreground"></div><div class="snow foreground layered"></div><div class="snow middleground"></div><div class="snow middleground layered"></div><div class="snow background"></div><div class="snow background layered"></div>
</div>
<div class="top-buttons-agileinfo"><a href="#">登录</a><a href="{% url 'register' %}" class="active">注册</a>
</div>
<h1 class="pad-bottom-1"> Sign In </h1>
<div class="main-agileits"><!--form-stars-here--><div class="form-w3-agile"><h2 class="sub-agileits-w3layouts">Sign In</h2><form action="{% url 'login' %}" method="post"><div class="input-group pos-relative"><span class="input-group-addon user-box"><i class="fa fa-envelope-o fa-fw"></i></span><input id="input-control" type="text" name="Username" placeholder="用户名或邮箱" required=""/></div><div class="input-group pos-relative"><span class="input-group-addon user-box" style=""><i class="fa fa-lock fa-fw"></i></span><input id="input-control" type="password" name="Password" placeholder="密码" required=""/></div><p class="p-bottom-w3ls left pad-bottom-3 pad-right-3"><a class="color-fff" href="{% url 'register' %}">点击注册</a></p><p class="p-bottom-w3ls left pad-bottom-3"></p><div class="submit-w3l"><input type="submit" value="登录"></div>{% csrf_token %}</form></div>
</div>
<!--//form-ends-here-->
<!-- copyright -->
<div class="copyright w3-agile"><p> © 2020 rainbowsea.xyz</p>
</div>
<!-- //copyright --><script type="text/javascript">//监听输入$('input[name=Username]').bind('input propertychange', function () {console.log($('input[name=Username]').val())});$('input[name=Password]').bind('input propertychange', function () {let password = $('input[name=Password]').val()if (password.length < 8) {layer.tips('您的密码长度不足8位,当前长度为:' + password.length, $('input[name=Password]'));} else {layer.close(layer.tips('您的密码长度不足8位,当前长度为:' + password.length, $('input[name=Password]')));}});$("input[type=submit]").click(function () {let password = $('input[name=Password]').val()if (password.length < 8) {alert("密码长度不够!")return false;}})var message = "{{ message }}"if (message){layer.msg(message)}
</script></body>
</html>

user-sign-up.html:

{% load static %}
<!DOCTYPE html>
<html>
<head><title>用 户 注 册 </title><meta name="viewport" content="width=device-width, initial-scale=1"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><script type="application/x-javascript"> addEventListener("load", function () {setTimeout(hideURLbar, 0);}, false);function hideURLbar() {window.scrollTo(0, 1);} </script><link href="{% static 'login&register/css/snow.css' %}" rel="stylesheet" type="text/css" media="all"/><link href="{% static 'login&register/css/style.css' %}" rel="stylesheet" type="text/css" media="all"/><!- Layui -><link href="{% static 'layui/css/layui.css' %}" rel="stylesheet"><!- ico -><link href="{% static "font-awesome/css/font-awesome.min.css" %}" rel="stylesheet" type="text/css" media="all"><!- js -><script type="text/javascript" src="{% static 'jQuery/jquery-3.3.1.js' %}"></script><script type="text/javascript" src="{% static 'jQuery/jquery-3.3.1.min.js' %}"></script><script type="text/javascript" src="{% static 'layui/layui.js' %}"></script><script type="text/javascript" src="{% static 'layui/layui.all.js' %}"></script><!-- google font --><link href="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet"><link href="//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" rel="stylesheet"><!-- //web font -->
</head>
<body>
<div class="snow-container"><div class="snow foreground"></div><div class="snow foreground layered"></div><div class="snow middleground"></div><div class="snow middleground layered"></div><div class="snow background"></div><div class="snow background layered"></div>
</div><div class="top-buttons-agileinfo"><a href="{% url 'login' %}" class="active">登录</a><a href="#">注册</a>
</div>
<h1 class="pad-bottom-1"> Sign Up Form </h1>
<div class="main-agileits"><!--form-stars-here--><div class="form-w3-agile"><h2 class="sub-agileits-w3layouts">登录</h2><form action="{% url 'register' %}" method="post">{% block input %}<div class="input-group pos-relative"><span class="input-group-addon ico-box-register"><i class="fa fa-envelope-o fa-fw"></i></span><input id="input-control" type="email" name="Username" placeholder="邮箱" required=""/></div><div class="input-group pos-relative"><span class="input-group-addon ico-box-register" style=""><i class="fa fa-lock fa-fw"></i></span><input id="input-control" type="password" name="Password" placeholder="密码" required=""/></div><div class="input-group pos-relative"><span class="input-group-addon ico-box-register" style=""><i class="fa fa-lock fa-fw"></i></span><input id="input-control" type="password" name="rPassword" placeholder="重复密码" required=""/></div><!-验证码 ->{{ UserRegister.captcha }}<!- 提交 -><div class="submit-w3l"><input type="submit" value="Sign up"></div>{% csrf_token %}{% endblock %}</form></div>
</div>
<!--//form-ends-here-->
<!- copyright ->
<div class="copyright w3-agile"><p> © 2020 rainbowsea.xyz</p>
</div>
<script>var msg = '{{ UserRegister.errors.captcha }}'if (msg) {layer.msg(msg)}/* 刷新验证码 */$('.captcha').click(function () {$.getJSON("/captcha/refresh/", function (result) {$('.captcha').attr('src', result['image_url']);$('#id_captcha_0').val(result['key'])});});$("#id_captcha_1").attr("placeholder", "请输入验证码")/*行为验证*/$('input[name=Password]').bind('input propertychange', function () {let password = $('input[name=Password]').val()if (password.length < 8) {layer.tips('您的密码长度不足8位,且至少应是数字、字母、等两种字符以上的组合', $('input[name=Password]'));} else {layer.close(layer.tips('您的密码长度不足8位,且至少应是数字、字母、等两种字符以上的组合', $('input[name=Password]')));}});$('input[name=rPassword]').bind('input propertychange', function () {let password1 = $('input[name=Password]').val()let password2 = $('input[name=rPassword]').val()if (password1 != password2) {layer.tips("您两次输入的密码不一致", $('input[name=rPassword]'));} else {layer.close(layer.tips("您两次输入的密码不一致", $('input[name=rPassword]')));}});$('input[name=captcha_1]').bind('input propertychange', function () {if ($('input[name=captcha_1]').val().length < 6) {layer.tips("验证码长度小于6,当前长度为" + $('input[name=captcha_1]').val().length, $('input[name=captcha_1]'), {tips: 3})}else {layer.close(layer.tips("验证码长度小于6,当前长度为" + $('input[name=captcha_1]').val().length, $('input[name=captcha_1]'), {tips: 3}))}});$('input[type=submit]').click(function () {let password1 = $('input[name=Password]').val()let password2 = $('input[name=rPassword]').val()let regNumber = /\d+/; //验证0-9的任意数字最少出现1次。let regString = /[a-zA-Z]+/; //验证大小写26个字母任意字母最少出现1次。let code = $('input[name=captcha_1]').val()if (password1 != password2) {layer.msg('两次密码输入不一致');return false;}if (password1.length < 8) {layer.msg('密码长度小于8');return false}if (code.length < 6) {layer.msg('验证码错误');return false;}if (regNumber.test(password1) && regString.test(password1)) {return true} else {layer.msg('密码至少应是数字和字母的两种组合');return false;}});var message = "{{ message }}"if (message){layer.msg('{{message}}');}
</script>
</body>
</html>
4、注册路由

先配置user下面的路由
user/urls.py:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-'''
@File    :   urls.py    
@Time :  2020/6/1 14:23
@Author :   c-cc
@Software :  PyCharm
'''from django.urls import pathfrom .views import *urlpatterns = [path('sign-in/', UserLoginView.as_view(), name="login"),path('sign-up/', UserRegisterView.as_view(), name="register"),# 活跃验证path('sign-up/activate/<str:activate_code>/', UserActivateView.as_view(), name="activate"),# 退出登录path('logout/', UserLogoutView.as_view(), name="logout"),
]

mysite/urls.py:

from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('user/', include('apps.user.urls')),# capthcapath('captcha/', include('captcha.urls')),
]

自此完成Django的登录和注册功能。我自己初学的时候也是遇到了很多的坑,现在写一比较详细的教程来帮助一下新手玩家不踩我踩过的坑。还有很多功能还没完成,如果有时间我也会继续更新。另外此项目我也部署到了我的个人服务器上附上地址::http://rainbowsea.xyz/,当然主页是我网上找的,自己写还是很恼火的,除此以外的大多都是我自己操作的,也、欢迎各位大佬莅临参观。如果发现了BUG,别告诉我,最近忙毕业设计…

转载请注明来源。

这篇关于基于Django3.0 实现注册、登录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/837621

相关文章

Spring IOC的三种实现方式详解

《SpringIOC的三种实现方式详解》:本文主要介绍SpringIOC的三种实现方式,在Spring框架中,IOC通过依赖注入来实现,而依赖注入主要有三种实现方式,构造器注入、Setter注入... 目录1. 构造器注入(Cons编程tructor Injection)2. Setter注入(Setter

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Spring IOC控制反转的实现解析

《SpringIOC控制反转的实现解析》:本文主要介绍SpringIOC控制反转的实现,IOC是Spring的核心思想之一,它通过将对象的创建、依赖注入和生命周期管理交给容器来实现解耦,使开发者... 目录1. IOC的基本概念1.1 什么是IOC1.2 IOC与DI的关系2. IOC的设计目标3. IOC

Python实现文件下载、Cookie以及重定向的方法代码

《Python实现文件下载、Cookie以及重定向的方法代码》本文主要介绍了如何使用Python的requests模块进行网络请求操作,涵盖了从文件下载、Cookie处理到重定向与历史请求等多个方面,... 目录前言一、下载网络文件(一)基本步骤(二)分段下载大文件(三)常见问题二、requests模块处理

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创