使用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. 转 rman-08120 以及查询隐含参数

    rman-08120 We need RMAN to automatically purge archivelogs from the FRA once they are applied to the ...

  2. HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化

    http://acm.hdu.edu.cn/listproblem.php?vol=49 给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k.则 ...

  3. Unity Unity脚本类为什么要尽量避免继承MonoBehaviour类?

  4. jQuery 结构的实现思路

    前提: 使用 JS 创建对象的最优办法,是 原型模式.   step1: 原型模式的基础使用方式     function fn(){}     fn.prototype = {}       var ...

  5. enable orgmode latex preview to support retina on mac

    Table of Contents 1. enable orgmode latex preview to support retina on mac 1.1. get the proper versi ...

  6. 构建第一个Spring Boot2.0应用之集成mybatis、Druid(七)

    一.环境: IDE:IntelliJ IDEA 2017.1.1 JDK:1.8.0_161 Maven:3.3.9 springboot:2.0.2.RELEASE 二.说明:      本文综合之 ...

  7. vim 粘贴复制操作

    原文链接:http://www.cnblogs.com/lansh/archive/2010/08/19/1803378.html vi编辑器有3种模式:命令模式.输入模式.末行模式.掌握这三种模式十 ...

  8. Android studio 配置忽略

    直接在Ignored Files选项里点击+号,在弹出的对话框选择第二项,然后依次输入上面包含的 .gradle .idea build 三个文件夹目录,再选择第一项,找到local.properti ...

  9. pysnmp程序

    功能 访问远程交换机snmp数据,写入本地influxdb数据库 #!/usr/bin/env python # -*- encoding: utf-8 -*- import os, yaml, ti ...

  10. SQLServer从其他表获取的数据更新该表的一部分

    在网上常见的是update  a  set  username  =  username  FROM b  on a.userid=b.userid,该更新语句是对a表中所有行进行更新.如果只更新一部 ...