本系列文章md笔记(已分享)次要探讨django商城我的项目开发相干常识。本我的项目利用Django框架开发一套前后端不拆散的商城我的项目(4.0版本)含代码和文档。性能包含前后端不拆散,不便SEO。采纳Django + Jinja2模板引擎 + Vue.js实现前后端逻辑,Nginx服务器(反向代理)Nginx服务器(动态首页、商品详情页、uwsgi服务器(美多商场业务场景),后端服务:MySQL、Redis、Celery、RabbitMQ、Docker、FastDFS、Elasticsearch、Crontab,内部接口:容联云、QQ互联、支付宝。

全套笔记和代码自取移步gitee仓库: gitee仓库获取残缺文档和代码

感兴趣的小伙伴能够自取哦,欢送大家点赞转发~


共 11 章,63 子模块

用户局部

应用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 osif 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 loggingfrom celery_tasks.main import appfrom .yuntongxun.sms import CCPlogger = 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_tasksclass 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仓库: gitee仓库获取残缺文档和代码

感兴趣的小伙伴能够自取哦,欢送大家点赞转发~