欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > DRF实操学习——商城

DRF实操学习——商城

2024/10/25 14:31:58 来源:https://blog.csdn.net/m0_51453764/article/details/142552267  浏览:    关键词:DRF实操学习——商城

DRF实操学习——商城

  • 1. 商城模型的设计
  • 2. 优化
    • 商品分类表
      • 1. 序列化器和查询集的优化
      • 2. 得到指定类目的所有商品
    • 商品表
      • 1. 视图的基础权限等配置
      • 2. 增加上传商品图片的接口
      • 3. 优选商品接口

分析:

  1. 商品分类表
  2. 商品表
  3. 商品图片表:一个商品有多张图片

1. 商城模型的设计

  1. 新建一个shopping的app
    在这里插入图片描述

  2. 在settings中注册该app
    在这里插入图片描述

  3. 创建模型,迁移映射

from django.db import modelsfrom utils.modelsMixin import ModelSetMixin# 商品分类表
class Classification(ModelSetMixin):name = models.CharField(max_length=40,verbose_name='分类名')# models.SET_NULL如果上级分类被删了,设置为空。外键关联自身parent = models.ForeignKey('self',on_delete=models.SET_NULL,null=True,blank=True,verbose_name='上级分类')class Meta:db_table = 'classification'verbose_name = '商品分类'verbose_name_plural = verbose_namedef __str__(self):return f'%s.%s' % (self.id,self.name)# 商品表
class Commodity(ModelSetMixin):STATUS_CHOICES = ((0,'未发布'),(1,'发布'),)name = models.CharField(max_length=40,verbose_name='商品名')caption = models.CharField(max_length=40,verbose_name='副标题')brand = models.CharField(max_length=40,verbose_name='品牌',null=True,blank=True)# 注:FloatField有计算精度的问题,如果有小数且参与计算,用DecimalField# 如果有小数,但是不怎么参与计算,那么可以使用FloatField# max_digits最大的位数 decimal_places小数为的最大位数price = models.DecimalField(max_digits=10,decimal_places=2,verbose_name='单价')stock = models.IntergerField(verbose_name='库存')pack = models.TextField(verbose_name='包装信息',null=True,blank=True)serviceafter_sale = models.TextField(verbose_name='售后服务',null=True,blank=True)sales = models.IntergerField(verbose_name='销量',default=0)comments = models.IntergerField(verbose_name='评价数',default=0)status = models.IntergerField(verbose_name='状态',default=0,choices=STATUS_CHOICES)detail = models.TextField(verbose_name='详情',null=True,blank=True)classification1 = models.ForeignKey(Classification,on_delete=models.PROTECT,verbose_name='一级分类',related_name='一级分类')classification2 = models.ForeignKey(Classification,on_delete=models.PROTECT,verbose_name='二级分类',related_name='二级分类')class Meta:ordering=['-sales','-comments','-create_time']db_table = 'commodity'verbose_name = '商品'verbose_name_plural = verbose_name# 商品图片表
class CommodityImg(models.Model):src = models.TextField(verbose_name='图片地址')priority = models.IntegerField(default=0,verbose_name='优先级')commodity = models.ForeignKey(Commodity,on_delete=models.CASCADE,verbose_name='商品')class Meta:ordering=['-priority','-id']db_table = 'commodity_img'verbose_name = '商品图'verbose_name_plural = verbose_name
  1. 创建序列化器
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *class ClassificationSerializer(ModelSerializer):class Meta:model = Classificationexclude = ['is_delete']class CommoditySerializer(ModelSerializer):class Meta:model = Commodityexclude = ['is_delete']class CommodityImgSerializer(ModelSerializer):class Meta:model = CommodityImgfields = '__all__'
  1. 创建视图
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from .serializers import *class ClassificationViewSet(ModelViewSet):queryset = Classification.objects.filter(is_delete=False)serializer_class = ClassificationSerializerclass CommodityViewSet(ModelViewSet):queryset = Commodity.objects.filter(is_delete=False)serializer_class = CommoditySerializerclass CommodityImgViewSet(ModelViewSet):queryset = CommodityImg.objects.filter(is_delete=False)serializer_class = CommodityImgSerializer
  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 = []
router = DefaultRouter()
router.register('classifications', ClassificationViewSet)
router.register('commodity', CommodityViewSet)
router.register('commodity_img', CommodityImgViewSet)
urlpatterns += router.urls
  1. 增加主路由
from django.contrib import admin
from django.urls import path, include
from rest_framework.documentation import include_docs_urlsurlpatterns = [path('admin/', admin.site.urls),path('drfstudy/', include('drfstudy.urls')),path('users/', include('users.urls')),path('school/', include('school.urls')),path('work/', include('work.urls')),path('community/', include('community.urls')),path('shopping/', include('shopping.urls')),path('docs/', include_docs_urls('DRF6项目接口文档'))  # 配置接口文档路由地址,文档标题
]

2. 优化

商品分类表

1. 序列化器和查询集的优化

  1. 序列化器的优化
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *class ClassificationSerializer(ModelSerializer):class Meta:model = Classificationexclude = ['is_delete']class ParentClassificationSerializer(ModelSerializer):# 要把子集展示出来,使用管理器。源模型小写_setclassification_set = ClassificationSerializer(many=True,read_only=True)class Meta:model = Classificationexclude = ['is_delete']
  1. 查询集的优化
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from .serializers import *class ClassificationViewSet(ModelViewSet):queryset = Classification.objects.filter(is_delete=False,parent=None)serializer_class = ParentClassificationSerializer
  1. 查询结果如下
    在这里插入图片描述
  2. 优化查询结果,继续修改序列化器
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *class ClassificationSerializer(ModelSerializer):class Meta:model = Classificationfields = ['id','name']class ParentClassificationSerializer(ModelSerializer):# 要把子集展示出来,使用管理器。源模型小写_setclassification_set = ClassificationSerializer(many=True,read_only=True)class Meta:model = Classificationfields = ['id','name','classification_set','parent']# 更改属性extra_kwargs = {# 将parent字段设置为只写,无法查看'parent':{'write_only':True} }

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

  1. 增加权限
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from .serializers import *
from rest_framework.permissions import IsAuthenticatedclass ClassificationViewSet(ModelViewSet):queryset = Classification.objects.filter(is_delete=False,parent=None)serializer_class = ParentClassificationSerializerpermission_classes = [IsAuthenticated]#更改权限装饰器,只有老师才有权限创建@wrap_permisssion(TeacherPermission) def create(self, request, *args, **kwargs):return ModelViewSet.create(self, request, *args, **kwargs)@wrap_permisssion(TeacherPermission)def update(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)@wrap_permisssion(TeacherPermission)def destroy(self, request, *args, **kwargs):return ModelViewSet.destroy(self, request, *args, **kwargs)

2. 得到指定类目的所有商品

在ClassificationViewSet中增加以下接口

    @action(methods=['get'],detail=True)def commodity(self,request,pk):try:classification = Classification.objects.filter(is_delete=False).get(id=pk)except Classification.DoesNotExist:return response(status=HTTP_404_NOT_FOUND)# 得到这个类目的所有商品,使用管理器# 判断类目是顶层类目还是子类目# 默认为顶层类目classification_attr = 'classification1'# 顶层类目 展示自身类目名classification_name = classification.name if classification.parent:classification_attr = 'classification2'classification_name =  f'{classification.parent.name}---{classification.name}'# 使用内置函数getattr获取属性data = getattr(classification,classification_attr).filter(is_delete=False,status=1)return Response({'classification':classification_name,'commodity':CommoditySerializer(data,many=True).data})

商品表

1. 视图的基础权限等配置

class CommodityViewSet(ModelViewSet):queryset = Commodity.objects.filter(is_delete=False)serializer_class = CommoditySerializerpermission_classes = [IsAuthenticated]# 重写get_queryset方法的场景:根据不同的操作场景设置不同的查询集def get_queryset(self):if self.action in ['list','retrieve']: #如果是查询,则只能返回已发布的商品return Commodity.objects.filter(is_delete=False,status=1)return self.queryset#更改权限装饰器,只有老师才有权限创建@wrap_permisssion(TeacherPermission) def create(self, request, *args, **kwargs):return ModelViewSet.create(self, request, *args, **kwargs)@wrap_permisssion(TeacherPermission)def update(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)@wrap_permisssion(TeacherPermission)def destroy(self, request, *args, **kwargs):return ModelViewSet.destroy(self, request, *args, **kwargs)

2. 增加上传商品图片的接口

from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN
from fdfs_client.client import Fdfs_client, get_tracker_conf
import logging
# 导入日志器
logger = logging.getLogger(__name__)# 创建FastDFS客户端对象
tracker_path = get_tracker_conf('utils/fastdfs/client.conf')
client = Fdfs_client(tracker_path)class CommodityViewSet(ModelViewSet):queryset = Commodity.objects.filter(is_delete=False)serializer_class = CommoditySerializerpermission_classes = [IsAuthenticated]# 重写get_queryset方法的场景:根据不同的操作场景设置不同的查询集def get_queryset(self):if self.action in ['list','retrieve']: #如果是查询,则只能返回已发布的商品return Commodity.objects.filter(is_delete=False,status=1)return self.queryset#更改权限装饰器,只有老师才有权限创建@wrap_permisssion(TeacherPermission) def create(self, request, *args, **kwargs):return ModelViewSet.create(self, request, *args, **kwargs)@wrap_permisssion(TeacherPermission)def update(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)@wrap_permisssion(TeacherPermission)def destroy(self, request, *args, **kwargs):return ModelViewSet.destroy(self, request, *args, **kwargs)@action(methods=['post'],detail=True)def img(self,request,pk):"""上传图片"""#获取商品try:commodity = self.get_queryset().get(id=pk)except Commodity.DoesNotExist:return Response(status=HTTP_404_NOT_FOUND)# 上传图片# 得到上传的文件数据file = request.FILES.get('file')# 判断是否有图片数据,文件类型是否是图片if not file or file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):# 不是,返回客户端传入数据错误return Response(status=HTTP_400_BAD_REQUEST)# 是,交给fastdfs,存储到可用的storage服务上# 得到文件后缀名,如果没有后缀名则默认为png类型try:images_ext_name = file.name.split('.')[-1]except Exception as e:logger.info('图片拓展名异常:%s' % e)images_ext_name = 'png'# 上传图片数据,通过字节流try:upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)except Exception as e:logger.error('图片上传出现异常:%s' % e)return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)else:if upload_res.get('Status') != 'Upload successed.':logger.warning('图片上传失败')return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)# 得到返回的file_idimage_name = upload_res.get('Remote file_id').decode()image_url = FASTDFS_SERVER_DOMAIN + image_name#保存图片地址CommodityImg.objects.create(src=image_url,commodity = commodity)#返回return Response({'data':image_url})

修改序列化器,优化查询结果

class CommodityImgSerializer(ModelSerializer):class Meta:model = CommodityImgfields = ['src']class CommoditySerializer(ModelSerializer):# classification1是外键关联的Classification表classification1_name = serializers.CharField(source='classification1.name',read_only=True)classification2_name = serializers.CharField(source='classification2.name',read_only=True)# 添加管理器:类名小写_setcommodityimg_set = CommodityImgSerializer(many=True,read_only=True)class Meta:model = Commodityexclude = ['is_delete']

优化后的查询结果如下:

在这里插入图片描述

3. 优选商品接口

在CommodityViewSet视图中增加以下接口

    @action(methods=['get'],detail=False)def optimization(self,request):"""优选商品接口,返回评论数最多的前五个商品"""# 这里使用order_by会覆盖在模型中使用的order_byqueryset = self.get_queryset().order_by('-comments').order_by('-create_time')# 使用切片返回前五条数据:0,1,2,3,4return Response(self.get_serializer(queryset[:5],many=True).data)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com