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

news/2024/9/27 21:18:06 标签: 学习, python, django

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

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

分析:

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

1.行政区划表的设计

在这里插入图片描述

  1. 在users的models中增加模型类Area,然后迁移映射
python"># 行政区划表
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. 编写序列化器
python">class AreaSerializer(ModelSerializer):
    class Meta:
        model = Area
        fields = ['id','name']
  1. 编写视图
python">class AreaViewSet(ModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer
  1. 增加路由
python">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的数据,即省份

python">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. 优化返回结果,修改序列化器
python"># 行政区划序列化器
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
python">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方法

python">    @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. 优化视图

python">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,然后迁移映射
python"># 行政区划表
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. 创建序列化器
python">class AddressSerializer(ModelSerializer):
    class Meta:
        model = Address
        exclude = ['is_delete']

  1. 编写视图
    分析:
    创建:当前登录用户
    修改:当前登录用户
    删除:当前登录用户
    查询:当前登录用户
    查询详情:当前登录用户
    所以我们可以对查询集进行处理
python">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. 增加路由
python">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. 收货地址表接口重写

python">	@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. 优化返回的数据

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

python">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> 方法

字段级别的校验

python">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.niftyadmin.cn/n/5679572.html

相关文章

Springboot集成MongoDb快速入门

1. 什么是MongoDB 1.1. 基本概念 MongoDB是一个基于分布式文件存储 [1] 的数据库。由C语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数…

(11)(2.1.2) DShot ESCs(四)

文章目录 前言 6 混合ESC协议 7 IOMCU DShot限制 8 参数说明 前言 DShot 是一种数字 ESC 协议&#xff0c;它允许快速、高分辨率的数字通信&#xff0c;可以改善飞行器控制&#xff0c;这在多旋翼和 quadplane 应用中特别有用。 6 混合ESC协议 虽然 ArduPilot 自动驾驶仪…

Pencils Protocol上线 Vaults 产品,为 $DAPP 深入赋能

Pencils Protocol是Scroll生态一站式综合收益平台&#xff0c;该平台以DeFi功能作为抓手&#xff0c;基于Farming、Vaults、Auction等功能不断向LRT、LaunchPad、AI、FHE、RWA等领域深入的拓展。 近期Pencils Protocol生态不断迎来重磅进展&#xff0c;一个是$DAPP通证先后在To…

Android 去掉SIM卡插拔出现的重启弹窗提示

调试过程中发现&#xff0c; 插入SIM卡会出现弹窗&#xff1a;SIM ADD: Restart your device to access the mobilenetwork. 拔掉SIM卡也会出现弹窗&#xff1a;SIM REMOVE: Restart your device to access the mobilenetwork. 分析下这块的实现&#xff0c;然后准备去掉&…

使用API有效率地管理Dynadot域名,设置域名服务器(NS)

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…

Vert.x,Databases

Vert.x数据库(访问)简介 Vert.x提供了数据库相关模块(扩展包)&#xff0c;方便我们通过异步方式访问数据库。数据库扩展主要包括&#xff1a;响应式数据库客户端(vertx-xxx-client)和通用JDBC客户端(vertx-jdbc-client)。 响应式数据库客户端是事件驱动和非阻塞的&#xff0c…

quill富文本插入表格quill-better-table

使用quill-better-table插件&#xff0c;官网GitCode - 全球开发者的开源社区,开源代码托管平台 安装 首先quill-better-table插件&#xff0c;官网有写需要 quills v2.0.0-dev3 我这里使用的是 quills v2.0.0-dev4&#xff0c;自行安装 然后就是安装我们的插件 quill-bett…

Unity八股总结

这里写目录标题 OnEnable、Awake、Start运行时的发生顺序&#xff1f;哪些可能在同一个对象周期中反复的发生&#xff1f;动态加载资源的方式?Unity3d脚本从唤醒到销毁有着一套比较完整的生命周期&#xff0c;请列出系统自带的几个重要的方法。物理更新一般放在哪个系统函数里…