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

本文介绍了如何在Django和DjangoRestFramework(DRF)的项目中实现收货地址的增删改查,包括序列化器、视图的配置,以及默认收货地址的设置。还涉及了使用阿里云短信服务发送验证码的接口实现,同时强调了权限验证、防止越权和验证码有效期的管理。
摘要由CSDN通过智能技术生成

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'),

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值