Django REST framework+Vue 打造生鲜电商项目(笔记二)

本文主要是介绍Django REST framework+Vue 打造生鲜电商项目(笔记二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

(转自https://www.cnblogs.com/derek1184405959/p/8768059.html)(有修改)

接下来开始引入django resfulframework,体现它的强大之处

一、首先,按照以前的做法,如果我们想把商品列表打包成JSON数据显示在首页,就是:

1、写view函数

# goods/view.pyfrom django.views.generic import View
from goods.models import Goodsclass GoodsListView(View):def get(self,request):#通过django的view实现商品列表页json_list = []#获取所有商品goods = Goods.objects.all()for good in goods:json_dict = {}#获取商品的每个字段,键值对形式json_dict['name'] = good.namejson_dict['category'] = good.category.namejson_dict['market_price'] = good.market_pricejson_list.append(json_dict)from django.http import HttpResponseimport json#返回json,一定要指定类型content_type='application/json'return HttpResponse(json.dumps(json_list),content_type='application/json')

2、配置url

from goods.view import GoodsListViewurlpatterns = [#商品列表页path('goods/',GoodsListView.as_view(),name='goods-list')
]

 访问http://127.0.0.1:8000/goods/  可以获取商品列表信息的json数据

二、django的serializer序列化model

当字段比较多时,一个字段一个字段的提取很麻烦,可以用model_to_dict,将model整个转化为dict

# goods/view.pyfrom django.views.generic import View
from goods.models import Goodsclass GoodsListView(View):def get(self,request):#通过django的view实现商品列表页json_list = []#获取所有商品goods = Goods.objects.all()from django.forms.models import model_to_dictfor good in goods:json_dict = model_to_dict(good)json_list.append(json_dict)from django.http import HttpResponseimport json#返回json,一定要指定类型content_type='application/json'return HttpResponse(json.dumps(json_list),content_type='application/json')

但是这样有个问题,就是ImageFieldFile 和add_time字段不能序列化

这时就要用到django的serializers

# goods/view_base.pyfrom django.views.generic import View
from goods.models import Goodsclass GoodsListView(View):def get(self,request):#通过django的view实现商品列表页json_list = []#获取所有商品goods = Goods.objects.all()import jsonfrom django.core import serializersfrom django.http import JsonResponsejson_data = serializers.serialize('json',goods)json_data = json.loads(json_data)#In order to allow non-dict objects to be serialized set the safe parameter to False.return JsonResponse(json_data,safe=False) # 注意,这里用的JsonResponse,这样就不用json.dumps了

注意,这里的图片路径是相对路径。还有其中的goods_desc之所以会那样是因为我们后台在添加数据用的是富文本,不是文本框,因此可以上传图片啥的,保存起来就是这个效果。

django的serializer虽然可以很简单实现序列化,但是有几个缺点

  (1)字段序列化定死的,要想重组的话非常麻烦

  (2)从上面截图可以看出来,images保存的是一个相对路径,我们还需要补全路径,而这些drf都可以帮助我们做到

以上写了这么多只是为了引入django rest framework和简单介绍django的序列化用法,下面就是重点讲解django rest framework了

 三、3种方式实现商品列表页

1、安装djangorestframework、coreapi(drf的文档支持)、django-guardian(drf对象级别的权限支持)

2、配置def文档的url

# urls.pyfrom rest_framework.documentation import include_docs_urlsurlpatterns = [#drf文档,title自定义path('docs',include_docs_urls(title='仙剑奇侠传')),
]

3、配置rest_framework

#setting.py

INSTALLED_APPS = ['rest_framework',
]
# urls.py

urlpatterns = [path('api-auth/',include('rest_framework.urls')),
]

4、第一种方法:APIview方式实现商品列表页

(1)goods文件夹下面新建serializers.py

用drf的序列化实现商品列表页展示,代码如下:

# goods/serializers.pyfrom rest_framework import serializersclass GoodsSerializer(serializers.Serializer):name = serializers.CharField(required=True,max_length=100)click_num = serializers.IntegerField(default=0)goods_front_image = serializers.ImageField()

这里的serializers.py可以理解成Django中在建立验证表单Form,联系这个知识点可以有助于理解。

(2)goods/views.py

# googd/views.pyfrom rest_framework.views import APIView
from goods.serializers import GoodsSerializer
from .models import Goods
from rest_framework.response import Responseclass GoodsListView(APIView):'''商品列表'''def get(self,request,format=None):goods = Goods.objects.all()goods_serialzer = GoodsSerializer(goods,many=True)return Response(goods_serialzer.data)

(3)drf的Modelserializer实现商品列表页

上面是用Serializer实现的,需要自己手动添加字段,如果用Modelserializer,会更加的方便,直接用__all__就可以全部序列化

# goods/serializers.pyfrom rest_framework import serializers
from .models import Goods#Serializer实现商品列表页
# class GoodsSerializer(serializers.Serializer):
#     name = serializers.CharField(required=True,max_length=100)
#     click_num = serializers.IntegerField(default=0)
#     goods_front_image = serializers.ImageField()#ModelSerializer实现商品列表页
class GoodsSerializer(serializers.ModelSerializer):class Meta:model = Goodsfields = '__all__'

外键category只显示分类的id,如果我们也要把外键对应的内容也显示出来。用serializers,它还可以嵌套使用,覆盖外键字段

# goods/serializers.pyfrom rest_framework import serializers
from .models import Goods,GoodsCategory#Serializer实现商品列表页
# class GoodsSerializer(serializers.Serializer):
#     name = serializers.CharField(required=True,max_length=100)
#     click_num = serializers.IntegerField(default=0)
#     goods_front_image = serializers.ImageField()class CategorySerializer(serializers.ModelSerializer):class Meta:model = GoodsCategoryfields = "__all__"#ModelSerializer实现商品列表页
class GoodsSerializer(serializers.ModelSerializer):#覆盖外键字段category = CategorySerializer()class Meta:model = Goodsfields = '__all__'

5、第二种方法:GenericView实现商品列表页

(1)mixins和generic一起使用

generic里面的GenericAPIView继承APIView,封装了很多方法,比APIView功能更强大

用的时候需要定义queryset和serializer_class
GenericAPIView里面默认为空

queryset = None

serializer_class = None
mixins里的ListModelMixin里面list方法帮我们做好了分页和序列化的工作,只要调用就好了

通过查看源码帮助自己更好的理解

class GenericAPIView(views.APIView):"""Base class for all other generic views."""# You'll need to either set these attributes,# or override `get_queryset()`/`get_serializer_class()`.# If you are overriding a view method, it is important that you call# `get_queryset()` instead of accessing the `queryset` property directly,# as `queryset` will get evaluated only once, and those results are cached# for all subsequent requests.queryset = Noneserializer_class = None# If you want to use object lookups other than pk, set 'lookup_field'.# For more complex lookup requirements override `get_object()`.lookup_field = 'pk'lookup_url_kwarg = None# The filter backend classes to use for queryset filteringfilter_backends = api_settings.DEFAULT_FILTER_BACKENDS# The style to use for queryset pagination.pagination_class = api_settings.DEFAULT_PAGINATION_CLASSdef get_queryset(self):"""Get the list of items for this view.This must be an iterable, and may be a queryset.Defaults to using `self.queryset`.This method should always be used rather than accessing `self.queryset`directly, as `self.queryset` gets evaluated only once, and those resultsare cached for all subsequent requests.You may want to override this if you need to provide differentquerysets depending on the incoming request.(Eg. return a list of items that is specific to the user)"""assert self.queryset is not None, ("'%s' should either include a `queryset` attribute, ""or override the `get_queryset()` method."% self.__class__.__name__)queryset = self.querysetif isinstance(queryset, QuerySet):# Ensure queryset is re-evaluated on each request.queryset = queryset.all()return queryset
GenericAPIView部分源码
class ListModelMixin(object):"""List a queryset."""def list(self, request, *args, **kwargs):queryset = self.filter_queryset(self.get_queryset())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)ListModelMixin源码
ListModelMixin源码

实现如下:

from goods.serializers import GoodsSerializer
from .models import Goods
from rest_framework.response import Response
from rest_framework import mixins
from rest_framework import genericsclass GoodsListView(mixins.ListModelMixin,generics.GenericAPIView):'商品列表页'queryset = Goods.objects.all()serializer_class = GoodsSerializerdef get(self,request,*args,**kwargs):    return self.list(request,*args,**kwargs) #由源码可知这里调用mixins.ListModelMixin里的list方法,
#而list又调用generics.GenericAPIView里的get_queryset方法,返回queryset,在进行序列化等处理返回

更进一步的优化:

可以直接继承ListAPIView,ListAPIView主要做了两件事:

(1)ListAPIView(mixins.ListModelMixin,GenericAPIView)    #继承了这两个类

(2)写好了get方法

这下,我们要获取商品列表页的信息,只要写三行代码就可以了

class GoodsListView(generics.ListAPIView):'商品列表页'queryset = Goods.objects.all()serializer_class = GoodsSerializer

6、第三种方法:viewsets和router完成商品列表页

主要用到viewsets中的GenericViewSet

 

ViewSets和Routers结合使用

因为通过GenericViewSet中的viewSetMixin,我们不需要通过在views.py中写函数来进行绑定,在router的帮助下,直接在urls.py中配置的时候来进行绑定,如下所示:  

# urls.pyfrom goods.views import GoodsListViewSet
from rest_framework.routers import DefaultRouterrouter = DefaultRouter()#配置goods的url
router.register(r'goods', GoodsListViewSet)urlpatterns = [#商品列表页re_path('^', include(router.urls)),
]

# views.pyclass GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):'商品列表页'# 分页pagination_class = GoodsPagination#这里必须要定义一个默认的排序,否则会报错queryset = Goods.objects.all().order_by('id')serializer_class = GoodsSerializer

如果不想用router的话,可改为:

# urls.py

goods_list = GoodsListViewSet.as_view({'get': 'list',}
)

7、drf的APIView、GenericView、viewsets和router的原理分析

genericViewSet 是最高的一层

往下

GenericViewSet(viewsets)     ----drf

  GenericAPIView                  ---drf

      APIView                        ---drf

      View            ----django

这些view功能的不同,主要的是有mixin的存在

mixins总共有五种:

  CreateModelMixin

  ListModelMixin

  UpdateModelMixin

  RetrieveModelMixin

  DestoryModelMixin

 以ListModelMixin为例:

如果不继承ListModelMixin的话,就无法将get和商品的列表关联起来,另外还有其中的分页等等,都无法实现。

还有其它几个mixin(增删改查局部),这些功能都是mixin做的

 我们一般都是用viewsets

ViewSet类与View类其实几乎是相同的,但提供的是read或update这些操作,而不是get或put 等HTTP动作。同时,ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身。

 Router提供了一种简单,快速,集成的方式来定义一系列的urls

8、添加分页功能

先看rest_framework/settings.py源码,里面可以找到如何配置:比如认证、权限和分页等等

添加分页功能,配置如下:

REST_FRAMEWORK = {#分页'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',#每页显示的个数'PAGE_SIZE': 10,
}

自定义分页功能

from rest_framework.pagination import PageNumberPaginationclass GoodsPagination(PageNumberPagination):'''商品列表自定义分页'''#默认每页显示的个数page_size = 10#可以动态改变每页显示的个数page_size_query_param = 'page_size'#页码参数page_query_param = 'page'#最多能显示多少页max_page_size = 100class GoodsListView(generics.ListAPIView):'商品列表页'pagination_class = GoodsPagination    #分页queryset = Goods.objects.all()serializer_class = GoodsSerializer

settings.py里面就不用设置了

9、drf的request和response介绍

REST framework 的 Request 类扩展了标准的 HttpRequest,并做了相应的增强,比如更加灵活的请求解析(request parsing)和认证(request authentication)。

Request 解析

REST framwork 的 Request 对象提供了灵活的请求解析,允许你使用 JSON data 或 其他 media types 像通常处理表单数据一样处理请求。

.data

request.data 返回请求主题的解析内容。这跟标准的 request.POST 和 request.FILES 类似,并且还具有以下特点:

  • 包括所有解析的内容,文件(file) 和 非文件(non-file inputs)。
  • 支持解析 POST 以外的 HTTP method , 比如 PUT, PATCH
  • 更加灵活,不仅仅支持表单数据,传入同样的 JSON 数据一样可以正确解析,并且不用做额外的处理(意思是前端不管提交的是表单数据,还是 JSON 数据,.data 都能够正确解析)。

.data 具体操作,以后再说~

.query_params

request.query_params 等同于 request.GET,不过其名字更加容易理解。

为了代码更加清晰可读,推荐使用 request.query_params ,而不是 Django 中的 request.GET,这样那够让你的代码更加明显的体现出 ----- 任何 HTTP method 类型都可能包含查询参数(query parameters),而不仅仅只是 'GET' 请求。

.parser

APIView 类或者 @api_view 装饰器将根据视图上设置的 parser_classes 或 settings 文件中的 DEFAULT_PARSER_CLASSES 设置来确保此属性(.parsers)自动设置为 Parser 实例列表。

通常不需要关注该属性......

如果你非要看看它里面是什么,可以打印出来看看,大概长这样:

[<rest_framework.parsers.JSONParser object at 0x7fa850202d68>, <rest_framework.parsers.FormParser object at 0x7fa850202be0>, <rest_framework.parsers.MultiPartParser object at 0x7fa850202860>]

包含三个解析器 JSONParserFormParserMultiPartParser

注意: 如果客户端发送格式错误的内容,则访问 request.data 可能会引发 ParseError 。默认情况下, REST framework 的 APIView 类或者 @api_view 装饰器将捕获错误并返回 400 Bad Request 响应。 如果客户端发送的请求内容无法解析(不同于格式错误),则会引发 UnsupportedMediaType 异常,默认情况下会被捕获并返回 415 Unsupported Media Type 响应。

Responses

与基本的 HttpResponse 对象不同,TemplateResponse 对象保留了视图提供的用于计算响应的上下文的详细信息。直到需要时才会计算最终的响应输出,也就是在后面的响应过程中进行计算。 — Django 文档

REST framework 通过提供一个 Response 类来支持 HTTP 内容协商,该类允许你根据客户端请求返回不同的表现形式(如: JSON ,HTML 等)。

Response 类的子类是 Django 的 SimpleTemplateResponseResponse 对象使用数据进行初始化,数据应由 Python 对象(native Python primitives)组成。然后 REST framework 使用标准的 HTTP 内容协商来确定它应该如何渲染最终响应的内容。

当然,您也可以不使用 Response 类,直接返回常规 HttpResponse 或 StreamingHttpResponse 对象。 使用 Response 类只是提供了一个更好的交互方式,它可以返回多种格式。

除非由于某种原因需要大幅度定制 REST framework ,否则应该始终对返回 Response 对象的视图使用 APIView 类或 @api_view 装饰器。这样做可以确保视图执行内容协商,并在视图返回之前为响应选择适当的渲染器。

创建 response

Response()

与普通 HttpResponse 对象不同,您不会使用渲染的内容实例化 Response 对象。相反,您传递的是未渲染的数据,可能包含任何 Python 对象。

由于 Response 类使用的渲染器不能处理复杂的数据类型(比如 Django 的模型实例),所以需要在创建 Response 对象之前将数据序列化为基本的数据类型。

你可以使用 REST framework 的 Serializer 类来执行序列化的操作,也可以用自己的方式来序列化。

构造方法: Response(data, status=None, template_name=None, headers=None, content_type=None)

参数:

  • data: 响应的序列化数据。
  • status: 响应的状态代码。默认为200。
  • template_name: 选择 HTMLRenderer 时使用的模板名称。
  • headers: 设置 HTTP header,字典类型。
  • content_type: 响应的内容类型,通常渲染器会根据内容协商的结果自动设置,但有些时候需要手动指定。

属性

.data

还没有渲染,但已经序列化的响应数据。

.status_code

状态码

.content

将会返回的响应内容,必须先调用 .render() 方法,才能访问 .content 。

.template_name

只有在 response 的渲染器是 HTMLRenderer 或其他自定义模板渲染器时才需要提供。

.accepted_renderer

用于将会返回的响应内容的渲染器实例。

从视图返回响应之前由 APIView 或 @api_view 自动设置。

.accepted_media_type

内容协商阶段选择的媒体类型。

从视图返回响应之前由 APIView 或 @api_view 自动设置。

.renderer_context

将传递给渲染器的 .render() 方法的附加的上下文信息字典。

从视图返回响应之前由 APIView 或 @api_view 自动设置。

标准 HttpResponse 属性

Response 类扩展于 SimpleTemplateResponse,并且响应中也提供了所有常用的属性和方法。例如,您可以用标准方式在响应中设置 header:

response = Response()
response['Cache-Control'] = 'no-cache'

.render()

与其他任何 TemplateResponse 一样,调用此方法将响应的序列化数据呈现为最终响应内容。响应内容将设置为在 accepted_renderer 实例上调用 .render(data,accepted_media_type,renderer_context) 方法的结果。

通常不需要自己调用 .render() ,因为它是由 Django 处理的。

 

转载于:https://www.cnblogs.com/linyuhong/p/9874509.html

这篇关于Django REST framework+Vue 打造生鲜电商项目(笔记二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/745506

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo