django rest framework 学习笔记-实战商城2

01收货地址模型类和视图定义_哔哩哔哩_bilibili 本博客借鉴至大佬的视频学习笔记


地址信息的管理:增删改查的实现

# 序列化器配置
class AddrSerializer(serializers.ModelSerializer):
    """收货地址的模型序列化器"""
    class Meta:
        model = Addr
        fields = '__all__'



# view 视图信息
class AddrView(GenericViewSet,
               mixins.ListModelMixin,
               mixins.CreateModelMixin,
               mixins.DestroyModelMixin,
               mixins.UpdateModelMixin):
    """收货地址管理视图"""
    queryset =  Addr.objects.all()
    serializer_class = AddrSerializer
    permission_classes = [IsAuthenticated,AddrPermissions]
    # filterset_fields = ('user',)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        # 通过请求过来的用户进行过滤
        queryset = queryset.filter(user=request.user)
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


# url 配置
# 添加地址和获取地址列表的路由
path('address/', AddrView.as_view({'post':'create','get':'list'}), name='address'),
# 删除和修改地址
path('address/<int:pk>/', AddrView.as_view({'delete':'destroy','put':'update'}), name='address'),

# 注册过滤器
'django_filters'

# 配置过滤器
REST_FRAMEWORK = {
    # 过滤器信息配置
    'DEFAULT_FILTER_BACKENDS':['django_filters.rest_framework.DjangoFilterBackend',]
}

默认收货地址的设置

#  如上 AddrView视图中增加默认地址函数
def set_default_addr(self,request,*args,**kwargs):
    """设置默认收货地址"""
    # 将获取的地址设置为默认
    obj =self.get_object()
    obj.is_default =True
    obj.save()
    # 将其他地址进行遍历为非默认
    queryset = self.get_queryset().filter(user=request.user)
    for item in queryset:
         if item !=obj:
            item.is_default =False
            item.save()
    return Response({'message':'设置成功'},status=status.HTTP_200_OK)

# url 文件配置
path('address/<int:pk>/default/', AddrView.as_view({'put': 'set_default_addr'}), name='address'),

云短信使用:网址云通信精选特惠

购买成功后进入控制台,搜索短信服务:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

点击当前的SDK信息,安装依赖

找到控制台的快捷操作,创建access_key_id 和access_key_secret

根据上面提供的demo代码优化结果: 参考博客:Django+DRF发送短信验证码--阿里云_django对接阿里云短信-CSDN博客

# -*- coding: utf-8 -*-
import json
from alibabacloud_dysmsapi20170525.client import Client
from alibabacloud_tea_openapi.models import Config
from alibabacloud_dysmsapi20170525.models import SendSmsRequest
from alibabacloud_tea_util.models import RuntimeOptions


class Sample:
    def create_client(self, access_key_id: str, access_key_secret: str):
        # 1. 创建一个配置对象
        """
        LTAI5tMLfxMgiu6gPycNcyTC
        H8LokjVLN50rDUCBqMss2juKpSownF
        """
        config = Config(
            # 必填,您的 AccessKey ID,
            access_key_id='xxx',
            # 必填,您的 AccessKey Secret,
            access_key_secret='xxx',
            endpoint=f'dysmsapi.aliyuncs.com'

        )
        # 2. 创建一个客服端
        client = Client(config)
        # 3. 创建短信对象
        send_sms_request = SendSmsRequest(
            sign_name='阿里云短信测试',
            template_code='SMS_154950909',
            phone_numbers='XXX',
            template_param='{"code":"1234"}'
        )
        # 4. 设置允许时间选项
        runtime = RuntimeOptions()
        # 5. 发送短信
        client.send_sms_with_options(send_sms_request, runtime)

class Send_SMS():
    #  access_key_id和 access_key_secret 为你的账号值
    access_key_id = 'access_key_id'
    access_key_secret = 'access_key_secret'
    endpoint = 'dysmsapi.aliyuncs.com'
    sign_name = '阿里云短信测试'
    template_code = 'SMS_154950909'

    def __init__(self):
        self.config = Config(
            # 必填,您的 AccessKey ID,
            access_key_id=self.access_key_id,
            # 必填,您的 AccessKey Secret,
            access_key_secret=self.access_key_secret,
            endpoint=self.endpoint
        )

    def send(self, mobile: str, code: str):
        """
        mobile: 手机号
        code:验证码
        """
        # 1. 创建一个客服端
        client = Client(self.config)
        send_sms_request = SendSmsRequest(
            phone_numbers=mobile,
            template_param=json.dumps({"code": code}),
            sign_name=self.sign_name,
            template_code=self.template_code,

        )
        # 2. 创建短信对象
        # 3. 设置允许时间选项
        runtime = RuntimeOptions()
        # 4. 发送短信
        client.send_sms_with_options(send_sms_request, runtime)


if __name__ == '__main__':
    # mobile为你的手机号
    # code 为你想要发到手机的验证码
    Send_SMS().send(mobile='xxx', code='1234')

验证码发送短信接口实现

# view 视图配置
class SendSmsView(APIView):
    """发送短信验证码"""
    def post(self,request):
        mobile = request.data.get('mobile','')
        pattern = '^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$'
        if not re.match(pattern,mobile):
            return Response({'error': '无效的手机号码'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        code  = self.get_random_code()
        result = Send_SMS().send(mobile,code)
        print(result)
        if result['code'] == 'OK':
            # 短信入库
            obj = VerifyCode.objects.create(mobile=mobile,code=code)
            result['codeID']=obj.id
            return Response(result,status=status.HTTP_200_OK)
        else:
            return Response({'error':'发送短信失败'},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    def get_random_code(self):
        """随机生成一个六位验证码"""
        code = ''
        for i in range(6):
            n= random.choice(range(9))
            code+=str(n)
        return code

# url 文件配置
path('sendsms/', SendSmsView.as_view(), name='sms'),

运行结果:

发送短信验证码限流配置

# view
from rest_framework.throttling import UserRateThrottle,AnonRateThrottle
# Create your views here.
class SendSmsView(APIView):
    """发送短信验证码"""
    # 设置限流,每分钟发送短信一次
    throttle_classes = (AnonRateThrottle,)

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        # 时间周期  second/minute/hour/day
        'anon': '1/minute',  # 未认证的用户 10/day sms
        'user': '1/minute'  # 认证的用户   100/day
    },
}

运行结果:

绑定手机接口实现 - 要求: 权限认证、防止越权、验证码三分钟(通过后三分钟从后天清除)

class UserView(GenericViewSet,mixins.RetrieveModelMixin):
    """用户相关的操作视图集"""
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated,UserPermissions] # 设置权限认证


    def bind_mobile(self,request,*args,**kwargs):
        code  =request.data.get('code') # 验证码
        codeID = request.data.get('codeID') # 验证码id
        mobile =request.data.get('mobile')
        if not code:
            return Response({'error':"验证码不可为空"},status=status.HTTP_400_BAD_REQUEST)
        if not codeID:
            return Response({'error':"验证码ID不可为空"},status=status.HTTP_400_BAD_REQUEST)
        if not mobile:
            return Response({'error':"手机号不可为空"},status=status.HTTP_400_BAD_REQUEST)
        if VerifyCode.objects.filter(id=codeID,code=code,mobile=mobile).exists():
            # 检验验证码是否过期,过期时间3分钟
            c_obj = VerifyCode.objects.get(id=codeID,code=code,mobile=mobile)
            # 获取验证码的创建的时间
            ct = c_obj.create_time.timestamp()
            # 当前时间的时间戳
            et = time.time()
            # 删除验证码,避免同一个验证码重复请求
            c_obj.delete()
            if ct + 180 < et:
                return Response({'error': "验证码已过期"}, status=status.HTTP_400_BAD_REQUEST)
        # else:
        #     return Response({'error': "无效的验证码,请重新获取验证码"}, status=status.HTTP_400_BAD_REQUEST)

        if User.objects.filter(mobile=mobile).exists():
            return Response({'error':"该手机号已被其他用户绑定"},status=status.HTTP_400_BAD_REQUEST)
        # 绑定手机号
        user = request.user
        user.mobile = mobile
        user.save()
        return Response({'error':"绑定成功"},status=status.HTTP_200_OK)

# 绑定手机号
path('<int:pk>/mobile/bind/', UserView.as_view({'put': 'bind_mobile'}), name='avatar_post'),

解绑手机号接口实现

    @staticmethod
    def verify_code(code,codeID,mobile):
        if not code:
            return {'error': "验证码不可为空"}
        if not codeID:
            return {'error': "验证码ID不可为空"}
        if not mobile:
            return {'error': "手机号不可为空"}
        if VerifyCode.objects.filter(id=codeID, code=code, mobile=mobile).exists():
            # 检验验证码是否过期,过期时间3分钟
            c_obj = VerifyCode.objects.get(id=codeID, code=code, mobile=mobile)
            # 获取验证码的创建的时间
            ct = c_obj.create_time.timestamp()
            # 当前时间的时间戳
            et = time.time()
            # 删除验证码,避免同一个验证码重复请求
            c_obj.delete()
            if ct + 180 < et:
                return {'error': "验证码已过期"}
        else:
            return {'error': "无效的验证码,请重新获取验证码"}
    def ubind_mobile(self,request,*args,**kwargs):
        code = request.data.get('code')  # 验证码
        codeID = request.data.get('codeID')  # 验证码id
        mobile = request.data.get('mobile')
        result = self.verify_code(code,codeID,mobile)
        if result:
            return Response(result,status=status.HTTP_400_BAD_REQUEST)
        # 解绑手机号,验证用户已绑定手机号
        user = request.user
        if user.mobile ==mobile:
            user.mobile = ''
            user.save()
            return Response({'error': "解帮成功"}, status=status.HTTP_200_OK)

        else:
            return Response({"error":"当前用户未绑定该号码"},status=status.HTTP_400_BAD_REQUEST)

# url 
# 解绑手机号
path('<int:pk>/mobile/ubind/', UserView.as_view({'put': 'ubind_mobile'}), name='ubind_mobile'),  # 检验token

修改昵称接口的实现 - 要求: 权限校验、防止越权

class UserView(GenericViewSet,mixins.RetrieveModelMixin):
    """用户相关的操作视图集"""
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated,UserPermissions] # 设置权限认证
 
    def update_name(self,request,*args,**kwargs):
        last_name = request.data.get('last_name')
        if not last_name:
            return Response({'error':"参数last_name 不可为空"},status=status.HTTP_400_BAD_REQUEST)
        user = self.get_object()
        user.last_name = last_name
        user.save()
        return Response({'message': "修改成功"}, status=status.HTTP_200_OK)

# url 
# 修改用户昵称
path('<int:pk>/name/', UserView.as_view({'put': 'update_name'}), name='update_name'),  # 检验token

修改用户邮箱接口

# view 
def update_email(self,request,*args,**kwargs):
    email = request.data.get('email')
    if not email:
        return Response({'error':"邮箱参数不可为空"},status=status.HTTP_400_BAD_REQUEST)
    pattern = '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
    if not re.match(pattern,email):
        return Response({'error':"邮箱格式错误"},status=status.HTTP_400_BAD_REQUEST)
    user = self.get_object()
    # 检验是否新旧一致
    if user.email ==email:
        return Response({'error':"不能和旧邮箱保持一致"},status=status.HTTP_200_OK)
    if User.objects.filter(email=email).exists():
        return Response({'error':"邮箱已被其他用户绑定"},status=status.HTTP_400_BAD_REQUEST)
    user.email = email
    user.save()
    return Response({'message': "修改成功"}, status=status.HTTP_200_OK)


# url
# 修改用户邮箱
path('<int:pk>/email/', UserView.as_view({'put': 'update_email'}), name='update_email'), 

用户密码接口修改与重置接口实现

要求:权限认证、防止越权、检验验证码、验证过期3分钟检验并通过后删除

# view
def update_password(self,request,*args,**kwargs):
    password = request.data.get('password')
    password_confirmation = request.data.get('password_confirmation')
    code = request.data.get('code')  # 验证码
    codeID = request.data.get('codeID')  # 验证码id
    mobile = request.data.get('mobile')
    result = self.verify_code(code,codeID,mobile)
    if result:
        return Response(result,status=status.HTTP_400_BAD_REQUEST)
    email = request.data.get('email')
    if not email:
        return Response({'error':"邮箱参数不可为空"},status=status.HTTP_400_BAD_REQUEST)
    user = self.get_object()
    # 检验是否新旧一致
    if user.mobile !=mobile:
        return Response({'error':"验证码有误"},status=status.HTTP_400_BAD_REQUEST)
    if not password:
        return Response({'error':"密码参数不可为空"},status=status.HTTP_400_BAD_REQUEST)
    if password !=password_confirmation:
        return Response({'error':"两次输入的密码不一致"},status=status.HTTP_400_BAD_REQUEST)

    # 修改用户密码 set_password 密码在数据中是加密的
    user.set_password(password)
    user.save()
    return Response({'message': "修改成功"}, status=status.HTTP_200_OK)

# url
# 修改用户密码
path('<int:pk>/password/', UserView.as_view({'put': 'update_password'}), name='update_password'),
相关推荐
VertexGeek12 分钟前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
二进制_博客1 小时前
Flink学习连载文章4-flink中的各种转换操作
大数据·学习·flink
codebolt1 小时前
ADS学习记录
学习
Komorebi.py2 小时前
【Linux】-学习笔记05
linux·笔记·学习
亦枫Leonlew2 小时前
微积分复习笔记 Calculus Volume 1 - 6.5 Physical Applications
笔记·数学·微积分
冰帝海岸7 小时前
01-spring security认证笔记
java·笔记·spring
小二·8 小时前
java基础面试题笔记(基础篇)
java·笔记·python
朝九晚五ฺ10 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
wusong99911 小时前
mongoDB回顾笔记(一)
数据库·笔记·mongodb
猫爪笔记11 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html