基于 Django2 实现邮箱注册登录功能
1. 开发环境
Python 3.6.5
Django 2.2
2. 项目功能
- 用户登录
- 邮箱注册
- 图形验证码
- 找回密码
- 修改密码
- 用户退出
3. 项目创建
首先创建项目:
django-admin startproject djangoLoginRegister
创建app:
python manage.py startapp users
(根目录新建apps文件夹,将以上 users 拖到 apps 下面)
文件路径设置:
在/settings.py中:
import os
import sys
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BASE_DIR)
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
4. 用户Models 设计
可以选择在系统用户表 users 的基础上扩展新的用户表,系统自动生成的users如下:
id: 主键
password: 密码
last_login: 最后登录时间
is_superuser: 是否是超级用户(管理员)
username: 用户名
first_name:
last_name:
email: 用户邮箱
is_staff: 后台管理员工
is_active: 是否激活(例如邮箱激活)
date_joined: 注册时间
在上面的基础上,扩展users
users/models.py 添加UserProfile(用户模型)和 EmailVerifyRecord(图形验证码模型):
from datetime import datetime
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
"""
用户信息
通过 AbstractUser 继承 django 原有自带的 User 类
"""
gender_choices = (
('male', '男'),
('female', '女'),
)
nick_name = models.CharField('昵称', max_length=50, default='')
birthday = models.DateField('生日',null=True,blank=True)
gender = models.CharField('性别',max_length=10,choices=gender_choices,default='female')
adress = models.CharField('地址',max_length=100,default='')
mobile = models.CharField('手机号',max_length=11,null=True,blank=True)
class Meta:
verbose_name = '用户信息'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
class EmailVerifyRecord(models.Model):
"""
图形验证码
"""
send_choices = (
('register','注册'),
('forget','找回密码')
)
code = models.CharField('验证码',max_length=20)
email = models.EmailField('邮箱',max_length=50)
send_type = models.CharField(choices=send_choices,max_length=10)
send_time = models.DateTimeField(default=datetime.now)
class Meta:
verbose_name = '邮箱验证码'
verbose_name_plural = verbose_name
注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
]
重载 AUTH_USER_MODEL
AUTH_USER_MODEL = 'users.UserProfile'
迁移数据库
python manage.py makemigrations
python manage.py migrate
执行 python manage.py runserver 查看是否能执行成功
5. 前端文件创建
创建templates文件夹,用了存放html文件;
创建static文件夹,用来存放js、css、image等静态文件
并在 settings.py 中设置 template 和 static 路径:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
6. 首页和登录页
6.1 页面
首页:
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>首页</title>
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/style.css' %}" rel="stylesheet">
</head>
<body>
<p> 首页 </p>
<div>
{% if name %}
欢迎,{{name}}
<a href="{% url 'logout' %}" > 退出 </a>
{% else %}
<a href="/login/" class="btn btn-success">登录</a>
<a href="/register/" class="btn btn-primary">注册</a>
{% endif %}
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</body>
</html>
登录页:
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form class="form-horizontal" role="form" action="{% url 'login' %}" method="post" >
<div class="form-group {% if login_form.errors.username %}errorput{% endif %}">
<label for="username" class="col-sm-2 control-label">name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" id="username" value="{{ login_form.username.value }}" placeholder="手机号/邮箱">
</div>
</div>
<div class="form-group {% if login_form.errors.password %}errorput{% endif %}">
<label for="password" class="col-sm-2 control-label">pass</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password" id="password" value="{{ login_form.password.value }}" placeholder="">
</div>
</div>
<div class="error btns login-form-tips" id="jsLoginTips">
{% for key,error in login_form.errors.items %}
<div style="color: red">
<span>{{ key }}</span>: <span>{{ error }}</span>
</div>
{% endfor %}
{% if msg %}
登录失败: {{ msg }}
{% endif %}
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Login</button>
</div>
</div>
{% csrf_token %}
</form>
<div style="text-align: left;">
<a href="{% url 'register' %}">去注册</a>
<a href="{% url 'forget_pwd' %}">忘记密码?</a>
</div>
</body>
</html>
6.2 路由设计
from django.conf.urls import url, include
from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView
from users.views import LoginView, LogoutView
urlpatterns = [
path('admin/', admin.site.urls),
url('^$', TemplateView.as_view(template_name='index.html'), name='index'),
url('^login/$', LoginView.as_view(), name='login'),
url('^logout/$', LogoutView.as_view(), name='logout'),
]
6.3 自定义表单验证规则
users目录下新建forms.py :
from django import forms
# 图形验证码
from captcha.fields import CaptchaField
class LoginForm(forms.Form):
"""
登录验证表单
"""
# 用户名密码不能为空
username = forms.CharField(required=True)
password = forms.CharField(required=True, min_length=3)
6.4 views 设计
class LogoutView(auth_views.LogoutView):
"""
退出
"""
def get(self, request, *args, **kwargs):
auth_logout(request)
return HttpResponseRedirect('/login/')
class LoginView(View):
"""
登录
"""
def get(self,request):
return render(request, 'login.html')
def post(self,request):
# 实例化
login_form = LoginForm(request.POST)
if login_form.is_valid():
# 获取用户提交的用户名和密码
# request.POST.get('username', '') 获取 username 如果不存在则指定默认值 ''
user_name = request.POST.get('username', '')
pass_word = request.POST.get('password', '')
print('user_name:', user_name)
print('pass_word:', pass_word)
# 成功返回user对象,失败None
user = authenticate(username=user_name, password=pass_word)
print(user)
# 如果不是null说明验证成功
if user is not None:
if user.is_active:
print('邮箱已激活,并且登录成功')
# 登录
login(request, user)
return render(request, 'index.html', {'name': user_name})
else:
print('邮箱未激活,登录失败')
return render(request, 'login.html', {'msg': '邮箱未激活,登录失败', 'login_form':login_form})
else:
print('登录失败')
return render(request, 'login.html', {'msg': '用户名或密码错误', 'login_form':login_form})
else:
return render(request, 'login.html', {'login_form':login_form})
7. 注册
用户注册流程为:填入邮箱、密码、验证码,点击注册,发送激活邮件,用户激活后,即注册成功。
7.1 register.html:
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
</head>
<body>
<form class="form-horizontal" role="form" method="POST" action="{% url 'register' %}">
<div class="form-group {% if register_form.errors.email %}errorput{% endif %}">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="email" name="email" placeholder="请输入邮箱">
</div>
</div>
<div class="form-group {% if register_form.errors.password %}errorput{% endif %}">
<label class="col-sm-2 control-label">pass</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="password" name="password" placeholder="请输入密码">
</div>
</div>
<div class="form-group {% if register_form.errors.captcha %}errorput{% endif %}">
<div class="col-sm-10">
{{ register_form.captcha }}
</div>
</div>
<div class="error btns" id="jsEmailTips">
{% for key,error in register_form.errors.items %}
{{ key }} - {{ error }}
{% endfor %}
{{ msg }}
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default">Register</button>
</div>
</div>
{% csrf_token %}
</form>
<div>
<a href="{% url 'login' %}">去登录</a>
</div>
</body>
</html>
7.2 图形验证码
使用 django 第三方库:
pip install django-simple-captcha
settings.py 中设置:
INSTALLED_APPS = [
...
'captcha',
]
添加url:
urlpatterns = [
path('captcha/',include('captcha.urls')),
]
迁移数据库:
python manage.py makemigrations
python manage.py migrate
注册页中显示验证码:
forms.py:
# 图形验证码
from captcha.fields import CaptchaField
class RegisterForm(forms.Form):
"""
注册验证表单
"""
email = forms.EmailField(required=True)
password = forms.CharField(required=True, min_length=3)
captcha = CaptchaField()
<div class="col-sm-10">
{{ register_form.captcha }}
</div>
7.3 注册 views
class RegisterView(View):
"""
注册
"""
def get(self,request):
register_form = RegisterForm()
return render(request, 'register.html', {'register_form': register_form})
def post(self, request):
register_form = RegisterForm(request.POST)
if register_form.is_valid():
user_name = request.POST.get('email', '')
# 用户已存在
if UserProfile.objects.filter(email = user_name):
return render(request, 'register.html', {'register_form': register_form, 'msg': '用户名已存在'})
pass_word = request.POST.get('password', '')
print('user_name:', user_name)
print('pass_word:', pass_word)
# 实例化一个 useProfile 对象
user_profile = UserProfile()
user_profile.username = user_name
user_profile.email = user_name
# 默认添加的用户是激活状态(is_active=1表示True),这里修改默认的状态为 False,只有用户邮箱激活后才改为True
user_profile.is_active = False
# 密码加密
user_profile.password = make_password(pass_word)
user_profile.save()
send_register_email(user_name, 'register')
return render(request, 'login.html')
else:
return render(request, 'register.html', {'register_form': register_form})
7.4 邮箱激活
settings.py中配置:
EMAIL_HOST = "smtp.qq.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = "****@qq.com" # 邮箱
EMAIL_HOST_PASSWORD = "************" # 邮箱授权码
EMAIL_USE_TLS= True
EMAIL_FROM = "****@qq.com" # 邮箱
定义发送邮件方法
在apps下新建 utils/email_send.py:
from random import Random
from django.core.mail import send_mail
from users.models import EmailVerifyRecord
from MxOnline190409.settings import EMAIL_FROM
def random_str(random_length=8):
str = ''
# 生成字符串的可选字符串
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
length = len(chars) - 1
random = Random()
for i in range(random_length):
str += chars[random.randint(0, length)]
return str
# 发送注册邮件
def send_register_email(email, send_type="register"):
# 发送之前先保存到数据库,到时候查询链接是否存在
# 实例化一个EmailVerifyRecord对象
email_record = EmailVerifyRecord()
# 生成随机的code放入链接
code = random_str(16)
email_record.code = code
email_record.email = email
email_record.send_type = send_type
email_record.save()
# 定义邮件内容:
email_title = ""
email_body = ""
if send_type == "register":
email_title = "django - 注册激活链接"
email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8888/active/{0}".format(code)
# 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,发件人邮箱地址,收件人(是一个字符串列表)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
# 如果发送成功
if send_status:
pass
if send_type == "forget":
email_title = "django - 找回密码"
email_body = "请点击下面的链接找回你的密码: http://127.0.0.1:8888/reset/{0}".format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
# 如果发送成功
if send_status:
pass
激活邮件 views:
class ActiveUserView(View):
"""
激活邮件
"""
def get(self, request, active_code):
# 查询邮箱验证记录是否存在
all_record = EmailVerifyRecord.objects.filter(code=active_code)
if all_record:
for record in all_record:
# 获取到对应邮箱
email = record.email
# 查找到邮箱对应的 user
user = UserProfile.objects.get(email=email)
user.is_active = True
user.save()
# 验证码不对的时候跳转到激活失败页面
else:
return render(request, 'email_active_fail.html')
# 激活成功 跳转到登录页面
return render(request, 'login.html')
7.5 添加注册和激活的url
from users.views import LoginView, LogoutView, RegisterView, ActiveUserView
urlpatterns = [
url('^register/$', RegisterView.as_view(), name='register'),
url('captcha/', include('captcha.urls')),
url(r'^active/(?P<active_code>.*)/$', ActiveUserView.as_view(), name="user_active"),
]
8. 找回密码
8.1 html
找回密码页面html:
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<title>忘记密码</title>
</head>
<body>
<form class="form-horizontal" role="form" method="POST" action="{% url 'forget_pwd' %}">
<div class="form-group {% if forget_form.errors.email %}errorput{% endif %}">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="email" name="email" value="{{ forget_form.email.value }}" placeholder="请输入邮箱">
</div>
</div>
<div class="form-group captcha1 {% if forget_form.errors.captchal %}errorput{% endif %}">
<label>输入验证码</label>
{{ forget_form.captcha }}
</div>
<div class="error btns" id="jsForgetTips">
{% for key,error in forget_form.errors.items %}
{{key}} - {{ error }}
{% endfor %}
{{ msg }}
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default">确认</button>
</div>
</div>
{% csrf_token %}
</form>
<div>
<a href="/">首页</a>
</div>
</body>
</html>
重置密码页面html:
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<title>重置密码</title>
</head>
<body>
<h4>修改密码</h4>
<p>已经通过验证,请设置新密码</p>
<form id="reset_password_form" action="{% url 'modify_pwd' %}" method="post">
<ul>
<li class="{% if modify_form.errors.password1 %}errorput{% endif %}">
<span class="">请输入新密码 :</span>
<input type="password" name="password1" id="pwd">
<i></i>
</li>
<input type="hidden" name="email" value="{{ email }}">
<li class="{% if modify_form.errors.password2 %}errorput{% endif %}">
<span class="">请确定新密码:</span>
<input type="password" name="password2" id="repwd">
<i></i>
</li>
<div class="error btns" id="jsPasswdResetTips">
{% for key,error in modify_form.errors.items %}
{{ key }}:{{ error }}
{% endfor %}
{{ msg }}
</div>
<li class="button">
<input type="submit" value="提交">
</li>
</ul>
{% csrf_token %}
</form>
<div>
<a href="/">首页</a>
</div>
</body>
</html>
8.3 urls
urlpatterns = [
# 忘记密码
url('^forget/$', ForgetPwdView.as_view(), name='forget_pwd'),
# 重置密码时发送的邮箱链接
url(r'^reset/(?P<active_code>.*)/$', ResetView.as_view(), name="reset_pwd"),
# 重置密码
url('^modify_pwd/$', ModifyPwdView.as_view(), name='modify_pwd'),
]
8.4 forms.py
class ForgetPwdForm(forms.Form):
"""
忘记密码表单
"""
email = forms.EmailField(required=True)
captcha = CaptchaField(error_messages={'invalid': '验证码错误'})
class ModifyPwdForm(forms.Form):
"""
重置密码
"""
password1 = forms.CharField(required=True, min_length=3)
password2 = forms.CharField(required=True, min_length=3)
8.5 views.py
class ForgetPwdView(View):
"""
找回密码
"""
def get(self,request):
forget_form = ForgetPwdForm()
return render(request,'forgetpwd.html',{'forget_form':forget_form})
def post(self, request):
forget_form = ForgetPwdForm(request.POST)
if forget_form.is_valid():
email = request.POST.get('email', '')
send_register_email(email, 'forget')
return render(request, 'send_success.html')
else:
return render(request, 'forgetpwd.html', {'forget_form': forget_form})
class ResetView(View):
"""
打开邮箱链接
"""
def get(self, request, active_code):
# 查询邮箱验证记录是否存在
all_record = EmailVerifyRecord.objects.filter(code=active_code)
if all_record:
for record in all_record:
email = record.email
return render(request, 'password_reset.html', {'email': email})
# 验证码不对的时候跳转到激活失败页面
else:
return render(request, 'active_fail.html')
return render(request, 'login.html')
class ModifyPwdView(View):
"""
重置密码
"""
def post(self, request):
modify_form = ModifyPwdForm(request.POST)
if modify_form.is_valid():
pwd1 = request.POST.get('password1', '')
pwd2 = request.POST.get('password2', '')
email = request.POST.get('email', '')
if pwd1 != pwd2:
return render(request, 'password_reset.html', {'email': email, 'msg': '两次输入密码不一致'})
user = UserProfile.objects.get(email = email)
user.password = make_password(pwd2)
user.save()
return render(request, 'login.html')
else:
email = request.POST.get('email', '')
return render(request, 'password_reset.html', {'email': email, "modify_form": modify_form})
最终数据库中的表格:
+------------------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| captcha_captchastore |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
| users_emailverifyrecord |
| users_userprofile |
| users_userprofile_groups |
| users_userprofile_user_permissions |
+------------------------------------+
基于 Django2 实现邮箱注册登录功能的更多相关文章
- 一步步开发自己的博客 .NET版(3、注册登录功能)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
- 8、ABPZero系列教程之拼多多卖家工具 添加手机注册登录功能
现在网站基本都用手机注册,很少用邮箱注册,本篇内容比较多,代码我会尽量加备注,有些操作需要连续添加几个文件才不报错,如果VS显示错误,请继续后续步骤. 前面已经有一篇文章讲到集成短信发送模块:http ...
- 详细讲解:使用tp3.2.3完成简单的注册登录功能
使用3.2.3进行了一个简单不过的注册登录功能,界面介绍: 1.注册: 2.登录: 3.登录成功后: 没错,就是简单的让你特别容易上手,上面运用到的知识有: (1)自动验证.自动完成 (2)sessi ...
- 基于SpringBoot从零构建博客网站 - 整合ehcache和开发注册登录功能
对于程序中一些字典信息.配置信息应该在程序启动时加载到缓存中,用时先到缓存中取,如果没有命中,再到数据库中获取同时放到缓存中,这样做可以减轻数据库层的压力.目前暂时先整合ehcache缓存,同时预留了 ...
- 基于javaweb人脸识别注册登录系统
---恢复内容开始--- 现在是2019年,人脸识别技术已经相当成熟了,百度自2017年发布人脸识别技术,已经被广泛应用,不管从现在的iphoneX掀起的面部解锁到手机应用端的各种人脸认证,这一技术已 ...
- JavaWeb 07_创建web项目连接MySQL实现注册登录功能
一.创建一个web项目,参照JW/01_创建web项目及部署 二.在NAVICat 里建数据库 db_01,建表tb_user ,字段UName .Pwd 三.在web下创建一个Directory, ...
- Node.js基于Express框架搭建一个简单的注册登录Web功能
这个小应用使用到了node.js bootstrap express 以及数据库的操作 :使用mongoose对象模型来操作 mongodb 如果没了解过的可以先去基本了解一下相关概念~ 首先注 ...
- 基于后端云的Android注册登录开发
APP开发离不开注册登录功能,但是注册登录功能开发需要后台数据库的支持,对于一些初学者或者对后台数据 不熟悉的同学来说可能会有些困难.本文介绍一下后端云: 1. Bmob是国内起步较早的云后端服务平台 ...
- vue2.0+koa2+mongodb实现注册登录
前言 前段时间和公司一个由技术转产品的同事探讨他的职业道路,对我说了一句深以为然的话: "不要把自己禁锢在某一个领域,技术到产品的转变,首先就是思维上的转变.你一直做前端,数据的交互你只知道 ...
随机推荐
- RTP 流媒体
RTMP协议是Adobe的私有协议,未完全公开,RTSP协议和HTTP协议是共有协议,并有专门机构做维护. RTMP协议一般传输的是flv,f4v格式流,RTSP协议一般传输的是ts,mp4格式的流. ...
- springboot部分常用注解
目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...
- WordCount作业修改
WordCount作业修改 github地址 需求说明 基本需求 功能说明 PSP 代码实现 字符总数查询 单词数查询 行数查询 总结 一.需求说明 1.基本需求 WordCount的需求可以概括为: ...
- ORACLE等待事件:SQL*Net message from client & SQL*Net message to client
在ORACLE当中有两个很常见的等待事件"SQL*Net message from client"与"SQL*Net message to client",两者 ...
- [20180928]如何能在11g下执行.txt
[20180928]如何能在11g下执行.txt --//链接问的问题: http://www.itpub.net/thread-2105467-1-1.html create table test( ...
- 个人对于 Maven 的理解
个人对于 Maven 的理解 Maven 一直都在使用, 但如果说是不是真的懂 Maven, 很难谈得上. 或许什么时候系统地学习一下, 但在那之前, 打算先记下自己目前对于 Maven 的理解, 之 ...
- NPOI 笔记
前言 文档:http://npoi.codeplex.com/documentation 示例:https://npoi.svn.codeplex.com/svn/ 下载:https://www.nu ...
- Java的基础知识四
一.Java 流(Stream).文件(File)和IO Java.io 包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io 包中的流支持很多种格式,比如:基 ...
- LeetCode算法题-Reverse Linked List(Java实现)
这是悦乐书的第192次更新,第195篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第51题(顺位题号是206).反转单链表.例如: 输入:1-> 2-> 3- ...
- C语言 求两数的最大公约数和最小公倍数
//作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ #include<stdio.h> //最大公约数 int gys(int x,int ...