【Django开发】前后端分离美多商城项目第4篇:用户部分,1. 判断用户名是否存在【附代码文档】

美多商城项目4.0文档完整教程(附代码资料)主要内容讲述:美多商城,项目准备1.B2B--企业对企业,2.C2C--个人对个人,3.B2C--企业对个人,4.C2B--个人对企业,5.O2O--线上到线下,6.F2C--工厂到个人。项目准备,配置1. 修改settings/dev.py 文件中的路径信息,2. INSTALLED_APPS,3. 数据库,4. Redis,5. 本地化语言与时区,6. 日志。用户部分,图片验证码。用户部分,使用Celery完成发送短信1. 判断用户名是否存在,2. 判断手机号是否存在:。用户部分,JWT起源,基于token的鉴权机制,JWT长什么样?,JWT的构成,总结,安装配置。用户部分,登录创建模型类,urllib使用说明。登录,登录回调处理创建模型类,urllib使用说明。登录,绑定用户身份接口创建模型类,urllib使用说明。邮件与验证,保存邮箱并发送验证邮件。收货地址,省市区地址查询。收货地址,使用缓存。商品部分,数据库表设计表结构,数据库模型类,1. 什么是FastDFS,2. 文件上传流程,3. 简易FastDFS构建。Docker使用,Docker简介1. 虚拟化,2. 什么是Docer,3. Docker组件,4 使用Docker做什么。Docker使用,安装与操作1. 在Ubuntu中安装Docker,2. 启动与停止,3. Docker镜像操作,4. Docker 容器操作,5. 将容器保存为镜像,6. 镜像备份与迁移。商品部分,FastDFS客户端与自定义文件存储系统1. FastDFS的Python客户端,2. 自定义Django文件存储系统,3. 在Django配置中设置自定义文件存储类,4. 添加image域名。商品部分,页面静态化。商品部分,商品详情页。商品部分,用户浏览历史记录1. 保存,2. 查看,获取商品列表数据。商品部分,商品搜索。购物车部分,购物车数据存储设计1. Redis保存已登录用户,2. Cookie保存未登录用户。购物车部分,查询购物车数据。购物车部分,登录合并购物车。订单部分,保存订单。支付,接入。Xadmin,用户权限控制1. 安装,2. 使用,1. 主从同步的定义,2. 主从同步的机制,3. 配置主从同步的基本步骤,4. 详细配置主从同步的方法。

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


全套教程部分目录:


部分文件图片:

用户部分

使用Celery完成发送短信

meiduo/meiduo_mall下创建celery_tasks用于保存celery异步任务。

在celery_tasks目录下创建config.py文件,用于保存celery的配置信息

broker_url = "redis://127.0.0.1/14"

在celery_tasks目录下创建main.py文件,用于作为celery的启动文件

from celery import Celery



# 为celery使用django配置文件进行设置


import os
if not os.getenv('DJANGO_SETTINGS_MODULE'):
    os.environ['DJANGO_SETTINGS_MODULE'] = 'meiduo_mall.settings.dev'



# 创建celery应用


app = Celery('meiduo')



# 导入celery配置


app.config_from_object('celery_tasks.config')



# 自动注册celery任务


app.autodiscover_tasks(['celery_tasks.sms'])

在celery_tasks目录下创建sms目录,用于放置发送短信的异步任务相关代码。

将提供的发送短信的云通讯SDK放到celery_tasks/sms/目录下。

在celery_tasks/sms/目录下创建tasks.py文件,用于保存发送短信的异步任务

import logging

from celery_tasks.main import app
from .yuntongxun.sms import CCP

logger = logging.getLogger("django")



# 验证码短信模板


SMS_CODE_TEMP_ID = 1

@app.task(name='send_sms_code')
def send_sms_code(mobile, code, expires):
    """
    发送短信验证码
    :param mobile: 手机号
    :param code: 验证码
    :param expires: 有效期
    :return: None
    """

    try:
        ccp = CCP()
        result = ccp.send_template_sms(mobile, [code, expires], SMS_CODE_TEMP_ID)
    except Exception as e:
        logger.error("发送验证码短信[异常][ mobile: %s, message: %s ]" % (mobile, e))
    else:
        if result == 0:
            logger.info("发送验证码短信[正常][ mobile: %s ]" % mobile)
        else:
            logger.warning("发送验证码短信[失败][ mobile: %s ]" % mobile)

在verifications/views.py中改写SMSCodeView视图,使用celery异步任务发送短信

from celery_tasks.sms import tasks as sms_tasks

class SMSCodeView(GenericAPIView):
    ...
        # 发送短信验证码
        sms_code_expires = str(constants.SMS_CODE_REDIS_EXPIRES // 60)
        sms_tasks.send_sms_code.delay(mobile, sms_code, sms_code_expires)

        return Response({"message": "OK"})

判断帐号是否存在

1. 判断用户名是否存在

后端接口设计:

请求方式: GET usernames/(?P<username>\w{5,20})/count/

请求参数: 路径参数

参数类型是否必传说明
usernamestr用户名

返回数据: JSON

{
    "username": "itcast",
    "count": "1"
}
返回值类型是否必须说明
usernamestr用户名
countint数量
后端实现

在users/views.py中定义视图

# url(r'^usernames/(?P<username>\w{5,20})/count/$', views.UsernameCountView.as_view()), 


class UsernameCountView(APIView):
    """
    用户名数量
    """
    def get(self, request, username):
        """
        获取指定用户名数量
        """
        count = User.objects.filter(username=username).count()

        data = {
            'username': username,
            'count': count
        }

        return Response(data)
前端实现

在js/register.js中修改

// 检查用户名
    check_username: function (){
            var len = this.username.length;
            if(len<5||len>20) {
                this.error_name_message = '请输入5-20个字符的用户名';
                this.error_name = true;
            } else {
                this.error_name = false;
            }
            // 检查重名
            if (this.error_name == false) {
                axios.get(this.host + '/usernames/' + this.username + '/count/', {
                        responseType: 'json'
                    })
                    .then(response => {
                        if (response.data.count > 0) {
                            this.error_name_message = '用户名已存在';
                            this.error_name = true;
                        } else {
                            this.error_name = false;
                        }
                    })
                    .catch(error => {
                        console.log(error.response.data);
                    })
            }
        },

2. 判断手机号是否存在:

后端接口设计:

请求方式: GET mobiles/(?P<mobile>1[3-9]\d{9})/count

请求参数: 路径参数

参数类型是否必须说明
mobilestr手机号

返回数据: JSON

{
    "mobile": "18512345678",
    "count": 0
}
返回值类型是否必须说明
mobilestr手机号
countint数量
后端实现

在users/views.py中定义视图

# url(r'^mobiles/(?P<mobile>1[3-9]\d{9})/count/$', views.MobileCountView.as_view()),


class MobileCountView(APIView):
    """
    手机号数量
    """
    def get(self, request, mobile):
        """
        获取指定手机号数量
        """
        count = User.objects.filter(mobile=mobile).count()

        data = {
            'mobile': mobile,
            'count': count
        }

        return Response(data)
前端实现

在js/register.js中修改

// 检查手机号
    check_phone: function (){
            var re = /^1[345789]\d{9}$/;
            if(re.test(this.mobile)) {
                this.error_phone = false;
            } else {
                this.error_phone_message = '您输入的手机号格式不正确';
                this.error_phone = true;
            }
            if (this.error_phone == false) {
                axios.get(this.host + '/mobiles/'+ this.mobile + '/count/', {
                        responseType: 'json'
                    })
                    .then(response => {
                        if (response.data.count > 0) {
                            this.error_phone_message = '手机号已存在';
                            this.error_phone = true;
                        } else {
                            this.error_phone = false;
                        }
                    })
                    .catch(error => {
                        console.log(error.response.data);
                    })
            }
        },

注册

1. 后端接口设计:

请求方式: POST /users/

请求参数: JSON 或 表单

参数名类型是否必须说明
usernamestr用户名
passwordstr密码
password2str确认密码
sms_codestr短信验证码
mobilestr手机号
allowstr是否同意用户协议

返回数据: JSON

{
    "id": 9,
    "username": "python8",
    "mobile": "18512345678",
}
返回值类型是否必须说明
idint用户id
usernamestr用户名
mobilestr手机号
视图原型
# url(r'^users/$', views.UserView.as_view()),


class UserView(CreateAPIView):
    """
    用户注册
    传入参数:
        username, password, password2, sms_code, mobile, allow
    """
    pass

2. 后端实现

在users/serializers.py中创建序列化器对象

class CreateUserSerializer(serializers.ModelSerializer):
    """
    创建用户序列化器
    """
    password2 = serializers.CharField(label='确认密码', write_only=True)
    sms_code = serializers.CharField(label='短信验证码', write_only=True)
    allow = serializers.CharField(label='同意协议', write_only=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'password2', 'sms_code', 'mobile', 'allow')
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }

    def validate_mobile(self, value):
        """验证手机号"""
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式错误')
        return value

    def validate_allow(self, value):
        """检验用户是否同意协议"""
        if value != 'true':
            raise serializers.ValidationError('请同意用户协议')
        return value

    def validate(self, data):
        # 判断两次密码
        if data['password'] != data['password2']:
            raise serializers.ValidationError('两次密码不一致')

        # 判断短信验证码
        redis_conn = get_redis_connection('verify_codes')
        mobile = data['mobile']
        real_sms_code = redis_conn.get('sms_%s' % mobile)
        if real_sms_code is None:
            raise serializers.ValidationError('无效的短信验证码')
        if data['sms_code'] != real_sms_code.decode():
            raise serializers.ValidationError('短信验证码错误')

        return data

    def create(self, validated_data):
        """
        创建用户
        """
        # 移除数据库模型类中不存在的属性
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']
        user = super().create(validated_data)

        # 调用django的认证系统加密密码
        user.set_password(validated_data['password'])
        user.save()

        return user

在users/views.py中定义视图

class UserView(CreateAPIView):
    """
    用户注册
    """
    serializer_class = serializers.CreateUserSerializer

3. 前端编写

修改js/register.js

// 注册
        on_submit: function(){
            this.check_username();
            this.check_pwd();
            this.check_cpwd();
            this.check_phone();
            this.check_sms_code();
            this.check_allow();

            if(this.error_name == false && this.error_password == false && this.error_check_password == false 
                && this.error_phone == false && this.error_sms_code == false && this.error_allow == false) {
                axios.post(this.host + '/users/', {
                        username: this.username,
                        password: this.password,
                        password2: this.password2,
                        mobile: this.mobile,
                        sms_code: this.sms_code,
                        allow: this.allow.toString()
                    }, {
                        responseType: 'json'
                    })
                    .then(response => {
                        location.href = '/index.html';    
                    })
                    .catch(error=> {
                        if (error.response.status == 400) {
                            if ('non_field_errors' in error.response.data) {
                                this.error_sms_code_message = error.response.data.non_field_errors[0];
                            } else {
                                this.error_sms_code_message = '数据有误';
                            }
                            this.error_sms_code = true;
                        } else {
                            console.log(error.response.data);
                        }
                    })
            }
        }

未完待续, 同学们请等待下一期

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/507047.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云服务器ECS经济型e实例怎么样?

阿里云服务器ECS经济型e系列是阿里云面向个人开发者、学生、小微企业&#xff0c;在中小型网站建设、开发测试、轻量级应用等场景推出的全新入门级云服务器&#xff0c;CPU处理器采用Intel Xeon Platinum架构处理器&#xff0c;支持1:1、1:2、1:4多种处理器内存配比&#xff0c…

vue3组合式函数

vue3的组合式函数的作用是封装和复用响应式状态的函数。只能在setup 标签的script标签汇总或者setup函数中使用。 普通的函数只能调用一次&#xff0c;但是组合式函数接受到响应式参数&#xff0c;当该值发生变化时&#xff0c;也会触发相关函数的重新加载。 如下 定义了一个…

算法(滑动窗口四)

1.串联所有单词的子串 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd","ef"]&#xff…

《QDebug 2024年3月》

一、Qt Widgets 问题交流 1. 二、Qt Quick 问题交流 1.Qt5 ApplicationWindow 不能使用父组件 Window 的 transientParent 属性 ApplicationWindow 使用 transientParent 报错&#xff1a; "ApplicationWindow.transientParent" is not available due to compone…

Android车载设备开发相关名词介绍

一、通讯相关 1、ECALL 如遭遇紧急情况&#xff0c;用户可按下该键以最高优先级接通呼叫中心&#xff0c;人工坐席将同时获取客户车辆的重要数据并协助驾驶员脱离危险。 实现原理 E-Call 的核心思想是利用车载卫星定位系统获取车辆的位置信息&#xff0c;在事故发生后&#x…

性能测试入门 —— 什么是性能测试PTS?

性能测试PTS&#xff08;Performance Testing Service&#xff09;是一款简单易用&#xff0c;具备强大的分布式压测能力的SaaS压测平台。 PTS可以模拟复杂的业务场景&#xff0c;并快速精准地调度不同规模的流量&#xff0c;同时提供压测过程中多维度的监控指标和日志记录。您…

输出100~200之间的素数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//实现素数判断函数&#xff1b; int Prime(int number) {//初始化变量值&#xff1b;int divided 2;int JudgementCondition 0;//循环判断素数&#xff1b;wh…

Git的使用【入门级】--下载github项目

1.下载Git Git for Windows Windows版本进入如上网址下载&#xff1a; 点击Download即可&#xff0c;建议下载到内存多的盘&#xff0c;我是下载到移动固态优盘中&#xff0c;以免C盘太挤。 验证Git是否安装成功&#xff1a; 双击git-bash.exe&#xff0c;命令行输入git versi…

【Django开发】0到1美多商城项目md教程第4篇:图形验证码,1. 图形验证码接口设计【附代码文档】

美多商城完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;欢迎来到美多商城&#xff01;&#xff0c;项目准备。展示用户注册页面&#xff0c;创建用户模块子应用。用户注册业务实现&#xff0c;用户注册前端逻辑。图形验证码&#xff0c;图形验证码接口设…

SQL,group by分组后分别计算组内不同值的数量

SQL&#xff0c;group by分组后分别计算组内不同值的数量 如现有一张购物表shopping 先要求小明和小红分别买了多少笔和多少橡皮&#xff0c;形成以下格式 SELECT name,COUNT(*) FROM shopping GROUP BY name;SELECT name AS 姓名,SUM( CASE WHEN cargo 笔 THEN 1 ELSE 0 END)…

关于Oracle VM VirtualBox无法查询IP地址的原因

1.如下&#xff0c;输入ifconfig却没有显示我框住的显示IP。 2.原因有可能&#xff1a; &#xff08;1&#xff09;主机没连上网络。 &#xff08;2&#xff09;虚拟机网络设置不正确。

Python问题列表

文章目录 1、使用pip安装的模块都存放到哪里了&#xff1f;2、安装fitz包报错&#xff0c;如何解决&#xff1f;3、python代码运行时&#xff0c;控制台输出乱码如何解决。4、vscode中第三方库不自动补齐 1、使用pip安装的模块都存放到哪里了&#xff1f; 答&#xff1a; pip是…

GLTFExporter是一个用于将3D场景导出为glTF格式的JavaScript库。

demo案例 GLTFExporter是一个用于将3D场景导出为glTF格式的JavaScript库。下面我将逐个讲解其入参、出参、属性、方法以及API使用方式。 入参&#xff08;Input Parameters&#xff09;: GLTFExporter的主要入参是要导出的场景对象和一些导出选项。具体来说&#xff1a; s…

Linux 入门及其基本指令(一文即入门)

目录 0 .引言 1. XShell 远程登录 Linux 1.1 云服务器 1.2. XShell 远程登陆 Linux 2. 详解 Linux 基本指令 2.1 ls 指令 2.2 pwd 指令 2.3 cd 指令 2.4 touch 指令 2.5 mkdir指令 2.6 rmdir指令 && rm 指令 0 .引言 如今&#xff0c;Linux 在服务器…

【Qt】系统相关(事件)

目录 一、概念二、事件处理三、鼠标事件1.鼠标点击事件2.鼠标释放事件3.鼠标移动事件 四、按键事件 一、概念 事件是应用程序内部或者外部产生的事情或者动作的统称。在Qt中使用一个对象来表示一个事件。所有的Qt事件均继承于抽象类QEvent。事件是由系统或者Qt平台本身在不同的…

【数据结构】——树和二叉树相关概念(全网超级详解)

创作不易&#xff0c;家人们来一波三连吧&#xff1f;&#xff01; 前言 世界上最大的树--雪曼将军树&#xff0c;这棵参天大树不是最长也不是最宽&#xff0c;是不是很奇怪&#xff0c;大只是他的体积是最大的&#xff0c;看图片肯定是感触不深&#xff0c;大家可以自己去看…

电脑卡顿怎么办?教你三招,轻松解决卡顿问题!

在现代社会&#xff0c;电脑已成为我们日常生活和工作中不可或缺的工具。然而&#xff0c;随着使用时间的增长&#xff0c;不少用户可能会遇到电脑卡顿的问题。卡顿不仅影响工作效率&#xff0c;还可能造成数据丢失等严重后果。本文将为大家介绍三种解决电脑卡顿问题的方法&…

使用 CSS 创建响应式图像滑块

使用 CSS 创建响应式图像滑块 效果展示 PC 端效果 移动端 / iPad 效果 CSS 知识点 媒体查询知识点复习position: absolute 的使用复习:nth-child 的使用复习 页面需求及实现思路 需求 页面会根据设备大小形成不同的布局方式当前展示图片放大并且展示对应的标题和描述其他…

智能公交调度管理服务系统

一、 背景 从上世纪末开始&#xff0c;为了缓解经济发展带来的道路交通方面的压力&#xff0c;绝大多数国家的公共交通部门方面进行了大量的投入&#xff0c;都在研发各种先进的技术来改善交通状况&#xff0c;其中包括了对公交 车的定位、对车辆实施全方位的虽然有的监控、自…

Leo赠书活动-23期 【Python数据分析】文末送书

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…