首页 > 其他分享 >Django实现的登录注册功能

Django实现的登录注册功能

时间:2024-04-09 23:31:26浏览次数:23  
标签:username code 登录 mobile self redis 验证码 Django 注册

1 前言

在Web开发中,用户登录和注册是最基本且必不可少的功能。Django,作为一个高级的Python Web框架,为我们提供了强大的工具和库来快速实现这些功能。下面,我将详细介绍如何使用Django来实现用户登录和注册功能。

2 功能介绍

该项目是使用django+bootstrp开发的项目,包含以下功能

  • 注册: 手机获取验证码、ModelForm数据验证、验证码redis超时处理,
  • 登录:手机验证码登录、账号密码登录、生成随机图片验证码、用户信息seesion处理

项目示例

1 账号密码登录
在这里插入图片描述
2 短信验证码登录
在这里插入图片描述
3 用户的注册
在这里插入图片描述
4 用户退出
在这里插入图片描述

3 申请容联云短信服务

登录和注册都需要一个短信的验证码,但是阿里、腾讯的短信服务申请太麻烦了,所有就申请了容联云短信服务,新用户有8元的免费额度只要项目不正式上线本地测试的话申请还是没有什么问题的,

容联云,全球智能通讯云服务商 (yuntongxun.com)

3.1 创建应用

在这里插入图片描述

3.2 创建短信模板

在这里插入图片描述

3.3 填写测试号码

在这里插入图片描述

3.4 安装sdk

 pip install ronglian_sms_sdk

3.5 发送短信的python代码

import json
from ronglian_sms_sdk import SmsSDK

# 容联云创建的应用中获取
accId = "应用的id"
accToken = "应用的token"
appId = "appid"


def send_sms(mobile, sms_code):
    """发送短信"""
    sdk = SmsSDK(accId, accToken, appId)
    tid = "1"
    try:
        resp = sdk.sendMessage(tid, mobile, (sms_code, ))
        res_json = json.loads(resp)
        if res_json.get("statusCode") == "000000":
            logger.info(f"向mobile[{mobile}]发送短信验证码[{sms_code}]成功")
        else:
            logger.info(f"发送短信失败:{resp}")
    except Exception as e:
        logger.error(f"发送短信失败:{e}")



if __name__ == '__main__':
    send_sms("平台测试手机号码", "9991")

运行脚本后手机会受到短信验证码,如下图
在这里插入图片描述

4 注册

在这里插入图片描述

注册分为两个部分:

  • 点击获取验证码:前端通过ajax发送请求到后端,后端生成随机验证码随机保存到redis中,同时调用短信服务发送短信到用户手机。
  • 点击注册:用户输入用户信息和验证码之后,后端进行校验,没有问题时保存到数据库,同时跳转到登录页面。
    在这里插入图片描述
    代码实现: 直截关键代码,完整代码跳转最后下载完整代码
# setting.py  django 使用redis
# 安装
pip install django-redis
# setting
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://192.168.1.200:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100, "encoding": "utf-8"}
            # "PASSWORD": "123",
        }
    }
}

from django_redis import get_redis_connection
def test_django_redis(request):
    # 可以直接从连接池中拿到连接
    redis=get_redis_connection()

    age = str(conn.get('age'), encoding='utf-8')
    # 设置过期时间
    redis.set('name','xiaoming',4)  
    redis.set('xxx',test_redis)
# view.py
from django.shortcuts import render
from django.http.response import JsonResponse
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django import forms
from django_redis import get_redis_connection
from users import models


class RegisterModelForm(forms.ModelForm):
    mobile_phone = forms.CharField(label="手机号",
                                   validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    password = forms.CharField(label="密码",
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': "密码长度不能小于8个字符",
                                   'max_length': "密码长度不能大于64个字符"
                               },
                               widget=forms.PasswordInput())
    confirm_password = forms.CharField(label="重复密码",
                                       min_length=8,
                                       max_length=64,
                                       error_messages={
                                           'min_length': "重复密码长度不能小于8个字符",
                                           'max_length': "重复密码长度不能大于64个字符"
                                       },
                                       widget=forms.PasswordInput())
    code = forms.CharField(label="验证码", widget=forms.TextInput())

    class Meta:
        model = models.UserInfo
        # fields = "__all__"
        fields = ["username", "email", "password", "confirm_password", "mobile_phone", "code"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)

    def clean_username(self):
        username = self.cleaned_data['username']
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
        return username

    def clean_email(self):
        email = self.cleaned_data['email']
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')
        return email

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        confirm_pwd = self.cleaned_data['confirm_password']
        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']

        # mobile_phone = self.cleaned_data['mobile_phone']

        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送,请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误,请重新输入')

        return code


def register(request):
    """用户注册视图"""
    if request.method == "GET":
        form = RegisterModelForm()
        return render(request, "users/register.html", {"form": form})
    elif request.method == "POST":
        form = RegisterModelForm(data=request.POST)
        if form.is_valid():
            form.save()
            logger.info(f"用户[{form.username}]注册成功")
            return JsonResponse({"status": True})
        logger.warning(f"用户[{form.username}]注册失败")
        return JsonResponse({"status": False, "error": form.errors})

主要是用Django的ModeForm对数据格式进行验证,以及注册时候的一些逻辑判断

5 短信验证码登录

在这里插入图片描述
短信验证码登录也分为两个部分

  • 点击获取验证码: 这个过程和用户的注册获取验证码类似,可以复用注册获取手机验证的代码
  • 点击登录: 输入手机号码和验证码之后,后端校验数据的有效性,将用户的信息保存在session中,跳转主页
    在这里插入图片描述
    代码实现: 直截关键代码,完整代码跳转最后下载完整代码
# view,py 中数据校验和逻辑处理
class LoginSMSForm(forms.Form):
    """短信验证码登录模板"""
    mobile_phone = forms.CharField(label='手机号',
                                   validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ]
                                   )
    code = forms.CharField(label='验证码',
                           widget=forms.TextInput())

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if not exists:
            raise ValidationError('用户未注册')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            return code
        redis = get_redis_connection()
        redis_code = redis.get(mobile_phone)  # 根据手机号去获取验证码
        if not redis_code:
            raise ValidationError('验证码失效或未发送,请重新发送')
        real_code = redis_code.decode('utf-8')
        if code.strip() != real_code:
            raise ValidationError('验证码错误,请重新输入')
        return code


def login_sms(request):
    """短信验证码登录"""
    if request.method == "GET":
        form = LoginSMSForm()
        return render(request, "users/login_sms.html", context={"form": form})
    elif request.method == "POST":
        form = LoginSMSForm(data=request.POST)
        if form.is_valid():
            logger.info(f"用户登录成功")
            return JsonResponse({"status": True})
        logger.warning(f"用户登录失败")
        return JsonResponse({"status": False, "error": form.errors})

主要是用Django的ModeForm对数据格式进行验证,以及登录时候的一些逻辑判断

6 用户密码登录

在这里插入图片描述
用户密码登录也分为两个部分

  • 生成图像验证码: 加载网页时会请求后端生成图像验证码的接口,后端会根据pillow画出一张图片返回给前端,同时将验证码保存到session中, 图像验证码具体怎么生成的看生成随机图片验证码-CSDN博客
  • 点击登录: 填好信息后点击登录,请求端口登录接口后端会对数据进行验证,成功后跳转。
    在这里插入图片描述

代码实现: 直截关键代码,完整代码跳转最后下载完整代码

class LoginForm(forms.Form):
    username = forms.CharField(label='用户名',
                               min_length=4,
                               max_length=64,
                               error_messages={
                                   'min_length': "密码长度不能小于4个字符",
                                   'max_length': "密码长度不能大于64个字符"
                               })
    password = forms.CharField(label="密码",
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': "密码长度不能小于8个字符",
                                   'max_length': "密码长度不能大于64个字符"
                               },
                               widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label='图片验证码',
                           widget=forms.TextInput())

    def __init__(self, request,  *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)

    def clean_username(self):
        username = self.cleaned_data["username"]
        if not models.UserInfo.objects.filter(username=username).exists():
            logger.warning("用户未注册")
            raise ValidationError("用户未注册")
        return username

    def clean_password(self):
        username = self.cleaned_data.get("username")
        if not username:
            logger.warning("用户名为空")
            return username
        password = self.cleaned_data['password']
        encrypt_password = md5(password)
        if not models.UserInfo.objects.filter(username=username, password=encrypt_password).exists():
            logger.warning("用户名或者密码错误")
            raise ValidationError("用户名或者密码错误")
        return encrypt_password

    def clean_code(self):
        code = self.cleaned_data["code"]
        session_code = self.request.session.get("image_code")
        if not session_code:
            logger.warning("验证码已过期, 请求重新获取")
            raise ValidationError("验证码已过期, 请求重新获取")
        if code.strip().upper() != session_code.strip().upper():
            logger.warning(f"验证码输入错误,{code}:{session_code}")
            raise ValidationError("验证码输入错误")
        return code


def login(request):
    """用户账号密码登录"""
    if request.method == "GET":
        form = LoginForm(request)
    else:
        form = LoginForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data["username"]
            user_obj = models.UserInfo.objects.filter(username=username).first()
            request.session["user_id"] = user_obj.id
            request.session.set_expiry(settings.SESSION_EXPIRY)
            logger.info("用户登录成功")
            return redirect("home")
        logger.warning("用户登录失败")
    return render(request, "users/login.html", context={"form": form})

主要是用Django的ModeForm对数据格式进行验证,以及登录时候的一些逻辑判断

6 运行项目

完整代码一下链接下载

【免费】Django+bootstrp实现用户的注册和登录功能资源-CSDN文库

# 1 下载代码解压
# 2 安装依赖
pip install -r requirement.txt
# 3 迁移数据库
python manage.py makemigrations
python manage.py migrate
# 4 登录容联云获取accId、accToken、appId替换sms.py
# 5 在setting中修改redis中的地址
# 4 启动项目
python manage.py runserver

另外安装redis的教程也可以看::Docket常见的软件部署1-CSDN博客

标签:username,code,登录,mobile,self,redis,验证码,Django,注册
From: https://blog.csdn.net/weixin_43413871/article/details/137571679

相关文章

  • Django开发踩坑(一)
    autoescape控制当前的自动转义行为。该标签以on或off作为参数,决定块内是否有自动转义行为。此区块以endautoescape结束标签关闭。示例:{%autoescapeon%}{{body}}{%endautoescape%}Django中自定义tag的使用在Django中,你可以通过创建一个自定义的模板标签......
  • Django便捷函数shortcuts
    一、Django便捷函数1、介绍包django.shortcuts收集助手函数和“跨”多级mvc的类,换句话说,为了方便起见,这些函数/类引入受控耦合。fromdjango.shortcutsimportrender,HttpResponse,redirect,reverse,resolve_url2、官方链接https://docs.djangoproject.com/zh-hans/3......
  • Django框架之中间件
    一、Django的生命周期二、Django中间件介绍1、什么是Django中间件?在Django中,中间件(middleware)是一个轻量级、插件式的框架,用于在Django请求和响应处理过程中进行拦截、处理和转换。中间件可以在处理请求之前和之后执行特定的逻辑,允许开发者对请求和响应进行全局性的处理,而无需......
  • Django框架之auth模块
    一、引入在我们创建完Django项目之后,点击urls.py会发现有一个path('admin/',admin.site.urls),的路由,那这个是什么呢?输入127.0.0.1::8000/admin我们可以看见这个管理员的登录页面那我们没有用户名和密码啊,这怎么登录进去?所以我们需要创建一个管理员(超级用户),在命令行输入pyt......
  • ssh远程不登录执行命令,不能执行alias 别名的命令
    前言全局说明ssh远程不登录执行命令,不能执行alias别名的命令一、bash的工作模式bash可以有不同的调出的方式,例如开机之后按Alt+F1~Alt+F6呼出不同的终端,输入账户密码进入的shell;ssh远程登陆到一台机器进行的shell;又或者在一个shell中执行bash命令又创建了一个s......
  • SSO单点登录逻辑
    网站的单点登录(SingleSign-On,SSO)逻辑旨在实现用户只需在一个地方进行一次身份验证,就能访问多个相互信任的应用系统或网站,无需在每个系统上单独登录。以下是单点登录的基本逻辑流程:1.用户访问受保护资源用户尝试访问某个集成到SSO体系中的应用(如应用A)。应用A检测到用户未登......
  • Django后端如何限制上传文件大小
    在Django中,对上传文件大小进行限制可以通过几种不同的方法来实现。这包括在表单层面、视图层面或通过设置Django项目的全局配置。以下是一些常用的方法:方法1:使用Django设置限制文件大小在Django的settings.py文件中,你可以设置DATA_UPLOAD_MAX_MEMORY_SIZE来限制上传文件的大......
  • python计算机毕设【附源码】基于html的校园网设计与实现(django+mysql+论文)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:在信息技术快速发展的今天,互联网已经成为人们获取信息、交流沟通的重要平台。对于学校而言,拥有一个功能齐全、操作简便的校园网系统显得尤为重要。基于HTML......
  • python计算机毕设【附源码】基于MySQL的房屋中介系统(django+mysql+论文)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:在当今社会,房地产市场的繁荣发展使得房屋中介行业成为了连接房东与租户、买家之间的重要桥梁。随着互联网技术的不断进步和普及,传统的房屋中介服务方式已经......
  • CentOS7设置ssh本机免密登录
    点击查看代码登出Connectiontoclone1closed.[[email protected]]#ll总用量16-rw-rw-r--.1rootroot3934月909:23authorized_keys-rw-------.1rootroot16794月719:16id_rsa-rw-r--r--.1rootroot3934月719:16id_rsa.pub-rw-r--r--.1r......