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

news/2025/2/19 10:24:17

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

 

文章来源:https://blog.csdn.net/qq_44238024/article/details/136222785
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.niftyadmin.cn/n/5387645.html

相关文章

选择 Python IDE(VSCode、Spyder、Visual Studio 2022和 PyCharm)

前言 当选择 Python 开发工具时&#xff0c;你需要考虑自己的需求、偏好和项目类型。下面是对VSCode、Spyder、Visual Studio 2022和 PyCharm的对比推荐总结&#xff1a; 结论 1、如果你专注于“数据科学”&#xff0c;选择SpyDer没错。 内容 Visual Studio Code (VS Code)…

曝iPhone 16 Pro加入两款全新配色:辨识度拉满

博主Majin Bu透露&#xff0c;苹果为即将推出的iPhone 16 Pro系列提供全新的两款配色&#xff0c;分别为“沙漠钛金”和“钛灰色”两种颜色选择。 该博主表示&#xff0c;“沙漠钛金”类似于2022年iPhone 14 Pro上提供的金色选项&#xff0c;但更深更重。另一方面&#xff0c;“…

贷齐乐系统最新版SQL注入(无需登录绕过WAF可union select跨表查询)

一、环境 已上传资源&#xff08;daiqile&#xff09; 二、代码解释 1.1Request 不管get请求还是post请求都可以接收到 1.2过滤的还挺多 1.3第二个WAF把数据分为两个了一个Key一个value&#xff0c;全是explode的功劳 1.4submit是if进入的前提 很明显走进来了 1.5那我们在这…

html的无语义标签:div span

html的无语义标签&#xff1a;div & span 无语义标签&#xff1a;div & span 标题&#xff0c;段落&#xff0c;图片等都是通过固定的标签来表示&#xff0c;标题用h1~h6标签来表示&#xff0c;段落用p标签来表示&#xff0c;图片用img标签来表示……每个标签都有自己…

【Hudi】索引

Hudi默认采用的HoodieBloomIndex索引&#xff0c;其依赖布隆过滤器来判断记录存在与否&#xff0c;当记录存在时&#xff0c;会读取实际文件进行二次判断&#xff0c;以便修正布隆过滤器带来的误差。 Hudi Bucket Index 在字节跳动的设计与实践] 1.1 索引的作用 在传统 Hive …

【MATLAB GUI】 5. 图像处理菜单(菜单编辑器)

看B站up主freexyn的freexyn编程实例视频教程系列36Matlab GUI的学习笔记 任务要求设计一个图像处理菜单&#xff0c;实现图像的打开导入、灰度处理、存储等功能 修改过文件名&#xff0c;所以运行的时候会有一点点报错&#xff0c;但是不影响运行 打开工具栏下边的菜单编辑器…

vscode【报错】yarn : 无法将“yarn”项识别为 cmdlet

问题 CMD下载完yarn可以查看到yarn版本&#xff0c;但是进入到vscode控制台报错无法识别&#xff0c;报错内容如下&#xff1a; vscode【报错】yarn : 无法将“yarn”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff…

ReactNative进阶(二十三)error: no type or protocol named ‘RCTBridgeModule’问题修复

文章目录 一、前言三、拓展阅读 一、前言 Jenkins组包RN技术栈实现的iOS应用时&#xff0c;遇到以下错误提示信息&#xff1a; error: no type or protocol named ‘RCTBridgeModule’ interface RCTEventDispatcher : NSObject <RCTBridgeModule>error: cannot find i…