使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站

项目支持支付宝支付(暂不支持微信支付),支持手机短信验证码注册, 支持第三方登录。集成了sentry错误监控系统。

本小节内容: Django原生以及使用drf 完成 商品列表页

django的view实现商品列表页

本章节很重要。

通过Django的fbv cbv (class base view)都可以实现。

更建议通过基于class的view编码,面向对象。

实现json返回。通过商品列表页学习大多数drf知识点

  1. 配置url
商品列表页
path('goods/', GoodsListView.as_view(),name="goods-list"),
  1. goods中新建一个view_base 来实现一个只通过Django实现的json返回。

查看Django的开发文档可以看到提供了很多view来减少我们的代码量

class GoodsListView(View):
def get(self, request):
"""
通过django的view实现商品列表页
"""
json_list = []
goods = Goods.objects.all()[:10] from django.forms.models import model_to_dict
for good in goods:
json_dict = model_to_dict(good)
json_list.append(json_dict) import json
from django.core import serializers
json_data = serializers.serialize('json', goods)
json_data = json.loads(json_data)
from django.http import HttpResponse, JsonResponse
return JsonResponse(json_data, safe=False)

model_to_dict 将model转换为字典,不用一个字段一个字段提取。

  • images field和 datetime直接dumps会出错
  • serializers 专门用于序列化,有了这个序列化,其实上面的model_to_dict都不用做了
moudle not callable

说明这是一个moudle我们不能直接调用,而应该进一步写明调用其中哪个方法。

 
mark
  1. 最基本方法问题,字段被一个一个的序列化。字段很多会很麻烦
  # for good in goods:
# json_dict = {}
# json_dict["name"] = good.name
# json_dict["category"] = good.category.name
# json_dict["market_price"] = good.market_price
# json_dict["add_time"] = good.add_time
# json_list.append(json_dict)
  1. 如果将addtime加入会报错,json.dumps无法自己完成。
TypeError: Object of type 'add_time' is not JSON serializable

推荐阅读:

https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138683221577998e407bb309542d9b6a68d9276bc3dbe000

Django本身的实现其实已经蛮简单了,那我们为啥要用drf

敲重点!!!

images这个图片保存的是一个相对路径,而我们需要加上前面的前缀。

这个工作drf可以完成补前缀工作。

字段序列化方式被定死了,重组麻烦。

文档生成,输入检测(你是放在request body还表单过来的)

使用drf完成商品列表页

商品列表页过基础知识

http://www.django-rest-framework.org/

强大的,灵活的,api

  • Web browsable API
  • Authentication policies 认证
  • Serialization that supports both ORM and non-ORM data sources.

序列化ORM 和 非ORM的数据源

regular function-based views 我们是用的cbv

 
mark

安装

coreapi (1.32.0+) - Schema generation support.
django-guardian (1.1.1+) - Object level permissions support.

对象级别的权限支持,coreapi支持文档

安装时报出utf-8 decode错误

修改虚拟环境中的

D:\CodeSpace\PythonEnvs\mxshop36\Lib\site-packages\pip\compat

大约75行

 
mark

如果出现错误,把这个地方改为gbk

引入我们的文档。

    # 自动化文档,1.11版本中注意此处前往不要加$符号
path('docs/', include_docs_urls(title='mtianyan生鲜超市文档'))

配置好了只要运行不报错验证成功。

Add 'rest_framework' to your INSTALLED_APPS setting.

INSTALLED_APPS = (
...
'rest_framework',
)
path('api-auth/', include('rest_framework.urls'))
 
mark

http://www.django-rest-framework.org/tutorial/3-class-based-views/

这里面官方给出了一个例子如何简单的写一个class view

class SnippetList(APIView):
"""
List all snippets, or create a new snippet.
"""
def get(self, request, format=None):
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)

将官方示例中的snippets用我们的Goods代替

 
mark

可以看到api view也是继承的view在它之上做了很多事。

from .models import Goods

写明引入当前目录下models中的Goos不容易重名失败。

可以自定义序列化的类。SnippetSerializer

modelform 和 form。modelform可以将字段直接转成html

现在drf里的Serializer是用来取代form开发的。modelfrom是针对html的,
Serializer是针对json的。

和之前的form一样。新建一个文件serializers.py

http://www.django-rest-framework.org/tutorial/1-serialization/

from rest_framework import serializers

class GoodsSerializer(serializers.Serializer):
name = serializers.CharField(required=True,max_length=100)
click_num = serializers.IntegerField(default=0)

字段太多了。我们先讲两个。

 
mark

因为我们是在用浏览器请求所以Drf会帮你渲染成网页格式

 
mark

这就是drf的Web browsable API

使用浏览器请求会返回html。

 
mark

get的时候指明json

 
mark
 
mark

接口的描述我们可以自行定义。

post过去的数据他能解析的格式。

因为我们是序列化的Goods,所以我们的Serializer要和goods model中保持一致

我们在Serializer中加上front image

 
mark

可以看到我们返回的json中,image字段全部加上了media前缀

前缀是通过我们setting的MEDIA_URL 来自动添加的。

drf的modelSerializer实现商品列表页功能

在drf的登录系统中user nonetype
注意检查这里需要返回的是username

    def __str__(self):
return self.username

之所以可以登录退出,
是因为这里配置了一个url

    # 调试登录
path('api-auth/', include('rest_framework.urls'))

goods/views.py添加:

  def post(self, request, format=None):
serializer = GoodsSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

接收前端request数据,交给GoodsSerializer进行验证,验证通过进行保存。

goods/serializers.py添加:

  def create(self, validated_data):
"""
Create and return a new `Goods` instance, given the validated data.
"""
return Goods.objects.create(**validated_data)

有了drf之后,他会把不管是用户GET post Body过来的数据
都会取到,放到data中。不需要对于get post 等做单独的处理。

save 会去调用Serializer里的create方法。

Django有form和modelform。那么Serializer是不是也有他的model

bingo

class GoodsSerializer(serializers.ModelSerializer):
class Meta:
model = Goods
# fields = ('category', 'goods_sn', 'name', 'click_num', 'sold_num', 'market_price')
fields = "__all__"
 
mark

外键会序列化成id。那我们通过id拿到对应的category

进行Serializer的嵌套使用。覆盖外键字段

class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = "__all__" class GoodsSerializer(serializers.ModelSerializer):
category = CategorySerializer() class Meta:
model = Goods
# fields = ('category', 'goods_sn', 'name', 'click_num', 'sold_num', 'market_price')
fields = "__all__"

GenericView 方式实现商品列表页和分页功能

使用更加上层的view写起来更简单。

使用Using mixins 和 generic view

GenericAPIView是在apiview的基础上加了filter 分页等一堆东西

我们不用添加createModelMixin是因为我们的商品数据是后台添加的,前台不会提交。

class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
"""
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)

list函数是在mixin中的,做了分页以及序列化。

不去重写定义get等http请求的方法默认你不接收这种方法

虽然上面已经很简单了,但是我们能不能更简单呢。

查看源码路径: D:/CodeSpace/PythonEnvs/mxshop36/Lib/site-packages/rest_framework

D:/CodeSpace/PythonEnvs/mxshop36/Lib/site-packages/rest_framework/generics.py

 
mark

这些view都是官方提供给我们的view

  • ListAPIview (获取列表)
  • CreateAPiView (创建一个)
  • Retrieve (获取某一条)
class GoodsListView(ListAPIView):
"""
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer

列表页通常都是要分页的,我们如何只通过setting的一个配置完成我们的分页。

所有关于restframework的配置要写在变量里

D:/CodeSpace/PythonEnvs/mxshop36/Lib/site-packages/rest_framework/settings.py

源码中的setting配置

 
mark

可以看到已经不提供默认的分页类了。我们需要自己指明

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10,
}
 
mark
 
mark

返回的数据有了变化。

有了count next页的url,将之前的数据放到了results中

 
mark

很神奇的是图片连域名都加上了。

问题来了: 这个域名怎么加上的,待探究。

将整个url提供实际是我们restful api的一个标准

class GoodsPagination(PageNumberPagination):
page_size = 12
page_size_query_param = 'page_size'
page_query_param = "page"
max_page_size = 100

最多100个。

goodslistview中添加

    pagination_class = GoodsPagination
 
mark

第几页,每一页取多少条都变成了可配置的。

Viewsets和router完成商品列表页

from rest_framework import viewsets
 
mark

可以看到它里面包含的

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):

它的内部之间pass,只是多继承了一个ViewSetMixin

ViewSetMixin中重写了as_view方法可以让我们的注册url变得更加简单

 
mark

在view的基础上设置了很多动作。动态设置Serializer

class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):

GenericViewSet只继承了api view,那么原来ListAPIView中的get方法的实现就没有了

class GoodsListView(mixins.ListModelMixin, viewsets.GenericViewSet):

ViewSets和Routers配套使用。

  1. 为了让我们更好看清我们使用的是viewset的实现.

goods/views.py

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

改名字

配置我们的url

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

将get请求绑定到list之上,类似于之前的

def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)

这样我们就不用自己再去绑定了。

配置url时就不用再加as_view()了

    # 商品列表页
path('goods/', goods_list,name="goods-list"),

但是我们可以更厉害一点,直接不用进行这个get 与list的绑定,它自动完成

我们要介绍的router就是做这个的。

from rest_framework.routers import DefaultRouter

router = DefaultRouter()

# 配置goods的url
router.register(r'goods', GoodsListViewSet)

url中配置

    # router的path路径
re_path('^', include(router.urls)),

router自动帮我们配置了get 和list,create 和 post的绑定

对于api view, GenericView viewset 和 router 的原理分析

理清我们的这些view他们之间的关系,以及listmodelMixin。
以及这些关系的组合使用,这样才能让我们更清楚什么时候使用哪种。

  1. genericViewSet 是最高的一层
GenericViewSet(ViewSet) -drf
GenericAPIView -drf
APIView -drf
View -django

这些view之间的差异就引出了drf中另一个核心点mixin

 
mark

可以看到源码中的mixin一共有五种

而各种view的差异,mixin就扮演着重要的角色

以ListModelMixin为例做区别,如果我们不去继承这个mixin它里面的这些方法的话。
就无法将get 和 list连接起来。无法连接,那么list中所作的所有功能都不能完成。

比如其中的

  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)

过滤,分页都将享受不到。

RetrieveModelMixin对于具体的商品信息进行了获取,序列化。这个在后面的商品详情页会介绍到。

UpdateModelMixin中对于部分更新还是全部更新进行了判断。

DestroyModelMixin用来连接我们的delete方法,在我们delete时有一些必要的操作,如设置返回状态204等。

上述这些功能都是mixin做的,而generic view并没有做。所以drf是通过两者的结合来实现。

GenericAPIView继承于views.APIView

Base class for all other generic views.是所有通用视图的基类

filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

在原本的apiview基础上添加了过滤,分页。如果不用genericapiview而用api view这些事情都要我们自己实现。

配合着genericview 加上mixin就能组合出更加强大的:

 
mark

如上图这些分别为某个单独操作设置的apiview

class RetrieveAPIView(mixins.RetrieveModelMixin,
GenericAPIView):
"""
Concrete view for retrieving a model instance.
具体的视图 对于 检索一个model实例
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)

get响应的是浏览器发过来的请求,浏览器发过来的请求只有http协议中规定的几种。
我们将get请求绑定上retrieve方法,就能享受到retrieve方法给我们的好处

我们可以自己写一个view来继承mixins.RetrieveModelMixin,GenericAPIView 但是我们
一定要把get 和 retrieve的绑定写上。

一般我们都会优先考虑下面组合好的这些apiview。还是满足不了要求,那就自己组合,满足这种配置方式就可以了。

Viewset有哪些好处?

generic下的各种变种view也是继承了genericAPIView,配合各种mixin进行组合工作。

它将具体的单个modelmixin(如:mixins.RetrieveModelMixin,)换成了ViewSetMixin

之前我们需要写函数将get等与retrieve等进行绑定。

ViewSetMixin的好处就是: 不需要我们通过方法来绑定。但是我们还是需要绑定关系的。

在url配置的时候进行绑定。

def as_view(cls, actions=None, **initkwargs)

他重写了as_view,接受参数,传递到对应的method 与 action进行绑定

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

将本来在代码中的绑定移到url中进行一个绑定的配置。

我们可以用router进行一个默认的绑定,router中的绑定其实和generic中的差不多

viewSetmixin还有一个很大的功能:

def initialize_request(self, request, *args, **kwargs):
"""
Set the `.action` attribute on the view,
depending on the request method.
"""
request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs)
method = request.method.lower()
if method == 'options':
# This is a special case as we always provide handling for the
# options method in the base `View` class.
# Unlike the other explicitly defined actions, 'metadata' is implicit.
self.action = 'metadata'
else:
self.action = self.action_map.get(method)
return request

为视图绑定动作,依赖于具体的request请求方法。这些action在我们后期进行动态Serializer时有很大好处。

 
mark

文章学习来自简书 作者:天涯明月笙
原文链接:https://www.jianshu.com/p/6a6fa62d8152

5- vue django restful framework 打造生鲜超市 -完成商品列表页(上)的更多相关文章

  1. 6- vue django restful framework 打造生鲜超市 -完成商品列表页(下)

    Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页下 drf中的request和response drf对于django的 ...

  2. 4- vue django restful framework 打造生鲜超市 -restful api 与前端源码介绍

    4- vue django restful framework 打造生鲜超市 -restful api 与前端源码介绍 天涯明月笙 关注 2018.02.20 19:23* 字数 762 阅读 135 ...

  3. 3- vue django restful framework 打造生鲜超市 - model设计和资源导入

    3- vue django restful framework 打造生鲜超市 - model设计和资源导入 使用Python3.6与Django2.0.2(Django-rest-framework) ...

  4. 7- vue django restful framework 打造生鲜超市 -商品类别数据展示(上)

    Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页 并没有将列表页的数据json 与前端的页面展示结合起来 讲解如果将dr ...

  5. 1- vue django restful framework 打造生鲜超市

    Vue+Django REST framework实战 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支 ...

  6. 2- vue django restful framework 打造生鲜超市 -环境搭建

    使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支付宝支付(暂不支持微信支付),支持手机短信验证码注册, ...

  7. 引爆潮流技术 Vue+Django REST framework打造生鲜电商项目

    引爆潮流技术Vue+Django REST framework打造生鲜电商项目 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受, ...

  8. Vue+Django REST framework打造生鲜电商项目

    1-1 课程导学 2-1 Pycharm的安装和简单使用 2-2 MySQL和Navicat的安装和使用 2-3 Windows和Linux下安装Python2和Python3 2-4 虚拟环境的安装 ...

  9. web前端Vue+Django rest framework 框架 生鲜电商项目实战视频教程 ☝☝☝

    web前端Vue+Django rest framework 框架 生鲜电商项目实战视频教程    web前端Vue+Django rest framework 框架 生鲜电商项目实战视频教程 学习 ...

随机推荐

  1. Helvetic Coding Contest 2016 online mirror B1

    Description The zombies are gathering in their secret lair! Heidi will strike hard to destroy them o ...

  2. APP请求超时问题-ios超时-android超时

    最近发现公司的app在高峰期超时严重.用wifi网络一直超时,但qq等却正常.换成手机卡网络正常. 起初以为是DNS解析问题. 后来抓包,发现DNS解析正常,可以得到正确的A记录. 但tcp retr ...

  3. LeetCode 230 Kth Smallest Element in a BST 二叉搜索树中的第K个元素

    1.非递归解法 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * ...

  4. 深刻理解Linux进程间通信(IPC)

    https://www.ibm.com/developerworks/cn/linux/l-ipc/ linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named pipe):管 ...

  5. spring构造注入

    Sping 结构体系结构4个核心组件 Beans:Bean是包装我们应用程序自定义对象Object的bject存有数据. Core: context在发现建立,维护Bean之间关系所需的一些工具.如资 ...

  6. Java 编码规范有感

    应小组要求,开发测试都需要考阿里编码规范,因此,相当于是突击了一下关于编码规范方面的知识,目前做的项目后期需要进行项目迁移,数据迁移,功能迁移... 各种迁移... 阿里巴巴编码规范(Java)考试地 ...

  7. springboot 学习笔记(八)

    springboot整合activemq,实现queue,topic同时支持 1.JMS中定义了两种消息模型:点对点(point to point, queue)和发布/订阅(publish/subs ...

  8. vue封装storage案例

    src/model/storage.js var storage={ set(key,value){ localStorage.setItem(key,JSON.stringify(value)); ...

  9. javascript数组属性及方法

    数组元素的添加 1. arrayt.splice(index,howmany,item1,.....,itemX) 向/从数组中添加/删除项目,然后返回被删除的项目 2. array.unshift( ...

  10. ArcGIS中经纬度数据转空间数据

    已有这样一批数据,后缀为.txt 或者.csv .现需要将其转化为空间数据. 转换过程: 打开ArcMap选择file——>Add Data——>Add XY Data 设置经纬度对应的字 ...