当前位置: 首页 > article >正文

DRF实操学习——收货地址的设计

DRF实操学习——收货地址的设计

  • 1.行政区划表的设计
  • 2. 行政区划表接口演示
    • 1.返回所有的省份
    • 2. 查询指定上级行政区划的所有子区划,以及展示自身区划
  • 3.行政区划表接口重写
  • 补充:前端请求逻辑
  • 4. 优化
  • 5.收货地址的设计
  • 6. 收货地址表接口重写
  • 7.优化
    • 1. 优化返回的数据
    • 2.增加额外的校验,重写 validate_<field_name> 方法

分析:

  1. 提供收货地址的选择:提供行政区划的三级联动查询,省——市——区
  2. 完成用户保存添加的收货地址

1.行政区划表的设计

在这里插入图片描述

  1. 在users的models中增加模型类Area,然后迁移映射
# 行政区划表
class Area(models.Model):
    name = models.CharField(max_length=20,verbose_name='名称')
    # 'self'建立外键关联自身主键。添加的上级行政区划必须是行政区划表中已有的数据
    # 省份没有上级行政区划 on_delete=models.SET_NULL删除时设置为空,null=True允许为空
    # blank=True,
    parent = models.ForeignKey('self',on_delete=models.SET_NULL,null=True,blank=True,verbose_name='上级行政区划')

    class Meta:
        db_table = 'area'
        verbose_name = '行政区划'
        verbose_name_plural = verbose_name
  1. 将省份等行政区划的基础数据配置进去
    在这里插入图片描述
  2. 编写序列化器
class AreaSerializer(ModelSerializer):
    class Meta:
        model = Area
        fields = ['id','name']
  1. 编写视图
class AreaViewSet(ModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer
  1. 增加路由
from django.urls import path
from rest_framework.routers import DefaultRouter
from rest_framework_jwt.views import obtain_jwt_token
from .views import *

urlpatterns = [
    path('login/', obtain_jwt_token),
    path('image/verification/<uuid:uuid>/', ImageVerifyView.as_view())
]
router = DefaultRouter()
router.register('users', UserViewSet)
router.register('area', AreaViewSet)
urlpatterns += router.urls

2. 行政区划表接口演示

分析:
把查询划分为两个接口

  1. 得到所有的省份:修改list视图函数,返回所有省份
  2. 把省份的id传入,修改详情路由,查询指定上级行政区划的所有子区划,以及展示自身区划

1.返回所有的省份

重写get_queryset方法,当操作为list操作时,查询所有parent=None的数据,即省份

class AreaViewSet(ModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer

    def get_queryset(self):
        if self.action == 'list':
        	#查询所有parent=None的数据,即省份
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

2. 查询指定上级行政区划的所有子区划,以及展示自身区划

  1. 优化返回结果,修改序列化器
# 行政区划序列化器
class AreaSerializer(ModelSerializer):
    """行政区划自身序列化器"""
    class Meta:
        model = Area
        fields = ['id','name']

# 增加一个新的行政区划的序列化器
class ParentSerializer(ModelSerializer):
    """
    行政区划自身序列化器及子级区划
    """
    # parent时外键关联自身,Area表时一对多查询
    # 生成管理器:源模型类名小写_set。通过管理器获取源模型类的所有数据
    area_set = AreaSerializer(many=True,read_only=True)
    class Meta:
        model = Area
        fields = ['id','name','area_set']

  1. 重写get_serializer_class
class AreaViewSet(ModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer

    def get_queryset(self):
        if self.action == 'list':
            # 查询所有parent=None的数据,即省份
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

    # get_serializer返回的是对象,get_serializer_class返回的是类
    # 重写get_serializer或get_serializer_class都可以
    def get_serializer_class(self):
        if self.action == 'retrive':
            #省份
            return ParentSerializer 
        else:
            return AreaSerializer

接口验证如下:
在这里插入图片描述

3.行政区划表接口重写

重写create、update、destroy方法

    @wrap_permisssion(RootPermission)#修改权限为root用户
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(RootPermission)#修改权限为root用户
    def update(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(RootPermission)#修改权限为root用户
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

补充:前端请求逻辑

在这里插入图片描述
选择省份的输入框,会向后端发送请求,获取所有省份,渲染到前端。比如选择湖北省,然后前端获取到湖北省的id,再次向后端发起请求,获取到湖北省下的所有区划。同理,在根据孝感市的id获取到孝感市下的所有区划。

4. 优化

分析:
特点:增加、删除、修改、更新操作少。查询操作多。
所以可以增加缓存功能,因为msyql性能相对来收比较慢,主要是做持久化数据。redis相当于是内存,高速读取数据库。可以将查询操作多的数据放在redis中,即将高频数据或临时数据缓存。

  1. 下载第三方库drf-extensions
    在这里插入图片描述

  2. 在settings中新增一个缓存配置
    在这里插入图片描述
    在这里插入图片描述

  3. 优化视图

from rest_framework_extensions.cache.mixins import CacheResponseMixin

#继承CacheResponseMixin,那么该视图下的所有操作都会缓存到area库中
class AreaViewSet(CacheResponseMixin, ModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer


  1. 发送查询请求后,查看redis的4号库,可以查看到数据,后续查询该数据时,会现在redis中查询数据是否存在,存在则直接返回,不存在,则去数据库中查询,然后再缓存在redis中
    在这里插入图片描述
    在这里插入图片描述

5.收货地址的设计

分析:
一个用户可以有多个收货地址:一对多关系。
定义收货地址模型类 ,新建一个收货地址表,外键关联用户表,保存是哪个用户创建的。

  1. 在users的models中增加模型类Address,然后迁移映射
# 行政区划表
class Address(ModelSetMixin):
    name = models.CharField(max_length=40,verbose_name='地址名')
    receiver = models.CharField(max_length=40,verbose_name='收货人')
    # on_delete=models.PROTECT受保护的,防止删除与该外键相关联的对象
    # 这里都关联了Area表,管理器都是area_set,管理器冲突,因此要重命名管理器名
    province = models.ForeignKey(Area,on_delete=models.PROTECT,verbose_name='省',related_name='province_address')
    city = models.ForeignKey(Area,on_delete=models.PROTECT,verbose_name='市',related_name='city_address')
    district = models.ForeignKey(Area,on_delete=models.PROTECT,verbose_name='区',related_name='district_address')
    place = models.CharField(max_length=40,verbose_name='详情地址')
    mobile = models.CharField(max_length=11,verbose_name='手机')

    user = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name='用户')

    class Meta:
        ordering = ['-update_time']
        db_table = 'adress'
        verbose_name = '收货地址'
        verbose_name_plural = verbose_name
  1. 创建序列化器
class AddressSerializer(ModelSerializer):
    class Meta:
        model = Address
        exclude = ['is_delete']

  1. 编写视图
    分析:
    创建:当前登录用户
    修改:当前登录用户
    删除:当前登录用户
    查询:当前登录用户
    查询详情:当前登录用户
    所以我们可以对查询集进行处理
class AddressViewSet(ModelViewSet):
    queryset = Address.objects.all()
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
    	# 之前是判断有没有权限,可以返回数据
        # 这里直接只能返回该用户的数据,爬虫无法找到
        return self.request.user.address_set.filter(is_delete=False)

补充另一种写法:
不在视图中写queryset
在这里插入图片描述

则需要在路由中补充basename
在这里插入图片描述

  1. 增加路由
from django.urls import path
from rest_framework.routers import DefaultRouter
from rest_framework_jwt.views import obtain_jwt_token
from .views import *

urlpatterns = [
    path('login/', obtain_jwt_token),
    path('image/verification/<uuid:uuid>/', ImageVerifyView.as_view())
]
router = DefaultRouter()
router.register('users', UserViewSet)
router.register('area', AreaViewSet)
# 如果在AddressViewSet不写queryset,则需要在路由中
# 增加basename,指定模型类
router.register('address', AddressViewSet, basename='address')
urlpatterns += router.urls

6. 收货地址表接口重写

	@auto_user
    def create(self, request, *args, **kwargs):
        max_count = 3
        if self.get_queryset().count() >= max_count:
            return Response({'detail':f'收货地址数量超过{max_count}条上限'},status=HTTP_400_BAD_REQUEST)
        return ModelViewSet.create(self, request, *args, **kwargs)


    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @destory_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

7.优化

1. 优化返回的数据

在这里插入图片描述
修改序列化器

class AddressSerializer(ModelSerializer):
    province_name = serializers.CharField(source='province.name',read_only=True)
    city_name = serializers.CharField(source='city.name',read_only=True)
    district_name = serializers.CharField(source='district.name',read_only=True)
    class Meta:
        model = Address
        exclude = ['is_delete']

查询结果如下:
在这里插入图片描述

2.增加额外的校验,重写 validate_<field_name> 方法

字段级别的校验

from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *
import re

class AddressSerializer(ModelSerializer):
    province_name = serializers.CharField(source='province.name',read_only=True)
    city_name = serializers.CharField(source='city.name',read_only=True)
    district_name = serializers.CharField(source='district.name',read_only=True)
    class Meta:
        model = Address
        exclude = ['is_delete']


    #自定义校验器,增加额外的校验功能:重写 validate_<field_name> 方法,字段级别的校验
    # 对手机号码进行校验
    def validate_mobile(self,value):
        if not re.match(r'1[3-9]\d{9}$',value):
            raise serializers.ValidationError('手机号码格式错误')
        return value

http://www.kler.cn/a/322679.html

相关文章:

  • 2024年11月16日 星期六 重新整理Go技术
  • 【免越狱】iOS砸壳 可下载AppStore任意版本 旧版本IPA下载
  • 【C语言】科技要闻。
  • 基于Java和Vue实现的上门做饭系统上门做饭软件厨师上门app
  • Linux最深刻理解页表于物理内存
  • Gin 框架中的路由
  • Oracle逻辑备份脚本【生产环境适用】
  • 深入浅出CSS盒子模型
  • 命令行基础指令速查(Linux/Mac适用)
  • 【HTTP 和 HTTPS详解】2
  • 【30天玩转python】并发编程
  • 黎巴嫩BP机爆炸事件启示录:我国应加快供应链安全立法
  • 理论-同步、异步、阻塞、非阻塞
  • 微信小程序 - 最新详细安装使用 Vant weapp UI 框架环境搭建详细教程
  • 蓝桥杯15届C/C++B组省赛题目
  • Python的包管理工具pip安装
  • 【前端】ES13:ES13新特性
  • 人工智能开发实时语音识别系统应用
  • 试用Debian12.7和Ubuntu24.4小札
  • 计算机网络--HTTP协议
  • 酒店智能门锁SDK接口pro[V10] 对接酒店收银-模块封装C#-SAAS本地化-未来之窗行业应用跨平台架构
  • C++ 类与对象(上)
  • 关于Mysql数据库的日常维护,包括配置、优化、备份、故障处理等工作的50道运维面试题
  • 关于使用/bin/sh -c 用于Dockerfile的Entrypoint的问题
  • 【第十五章:Sentosa_DSML社区版-机器学习之关联规则】
  • 高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十)高翔书中的细节:参考链接;卫星导航;ESKF