本文主要是介绍基于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®ister/css/snow.css' %}" rel="stylesheet" type="text/css" media="all"/><link href="{% static 'login®ister/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®ister/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®ister/css/snow.css' %}" rel="stylesheet" type="text/css" media="all"/><link href="{% static 'login®ister/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 实现注册、登录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!