Django-- (五) Django接口开发

1、前后端分离

1.1 传统的开发模式

传统的开发模式流程:根据url访问视图函数,在视图函数中进行逻辑判断、调用数据库、渲染HTML,最后再向浏览器返回HTML页面。之前功能的开发使用的就是传统开发模式。但有时候我们需要将这些内容在移动端(手机APP)或者其他设备上显示,显然使用传统的开发方式工作量太大,为了解决这个问题,可以使用前后分离开发模式。

1.2 前后端分离模式

前后端分离模型指的是后端只负责返回数据,不再负责渲染页面。前端负责渲染数据。

2、ajax

2.1 ajax介绍

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步JavaScript和XML”。即使用JavaScript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)还有JSON数据。
AJAX还有一个最大的特点就是,当服务器响应时,不用刷新整个浏览器页面,而是可以局部刷新。这一特点给用户的感受是在不知不觉中完成请求和响应过程。

2.2 ajax格式

使用原生的JavaScript 使用AJAX 比较麻烦,我们采用 jQuery 实现 AJAX 请求。

2.2.1 语法
$.ajax({
    url: url,  //请求的url
    type: "get",  //请求类型
    data: {"goodstype_id": 1},  //发送请求时携带的数据
    success: function (data) {  //请求成功时调用的函数,data是请求成功后返回的数据
    console.log(data)
    },
    error: function (error) {  //请求失败时调用的函数,error是请求失败后的错误信息
    console.log(error)
    }
})
2.2.2 参数介绍
参数描述
url发送请求的地址
type请求方式(“POST” 或 “GET”), 默认为 “GET”。注意:其它 HTTP 请求方法如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
data发送到服务器的数据。格式 {key:value,key:value}
error请求失败时调用此函数。
success请求成功后的回调函数。参数:由服务器返回数据
dataType预期服务器返回的数据类型。如果不指定,浏览器会智能判断。
可用值:
“xml”: 返回 XML 文档,可用 jQuery 处理。
“html”: 返回纯文本 HTML 信息;
“script”: 返回纯文本 JavaScript 代码。
“json”: 返回 JSON 数据 。

3、Vue—前端渲染

使用ajax异步请求之后可以把请求到的数据渲染到页面,但这个步骤太过繁琐,为了解决这个问题,从而使用vue框架。Vue 是一套用于构建用户界面的JavaScript框架,前端使用Vue的目的就是把AJAX里面的数据绑定到前端。

3.1 下载引用

下载之后直接引用即可

第一个脚本文件是vue脚本文件,第二个文件vue-resource是使用vue发送异步请求时要导入的文件

3.2 创建视图部分
def get_two_goods(request):
    """获取最新的两条数据"""
    goods_type = request.GET.get("goods_type")
    goods_list = Goods.objects.filter(goodstype=goods_type).order_by("-id")[:2]
    result = [{"id": goods.id, "name": goods.name, "price": goods.price, "picture": goods.picture.name} for goods in goods_list]
    # safe: 默认只支持返回字典类型数据,设置为false可以返回其他类型数据
    # json_dumps_params:设置是否转换成ASCII编码,不转则为中文
    return JsonResponse(result, safe=False, json_dumps_params={"ensure_ascii": False})
3.3 创建脚本并渲染
3.3.1 符号冲突

由于vue的变量也是用{{}}符号,和Django会有冲突。解决方法有两种

方法一:设置Django的verbatim标签,Django对标签内的变量不再识别

{% verbatim %}
    <div id="content">{{ message }}</div>
{% endverbatim %}

方法二:修改vue变量的符号

<div id="content">[[ message ]]</div>
new Vue({
    "el": "#content",
    "delimiters": ["[[","]]"],
    "data":{
        "message": "123"
    }
})
3.3.2 渲染数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<script src="/static/buyer/js/vue.min.js"></script>
<script src="/static/buyer/js/vue-resource.min.js"></script>
<body>

<div id="content">
    [[ message ]]
</div>

</body>
<script>
    new Vue({
        "el": "#content", //id下的dom与vue绑定
        "delimiters": ["[[","]]"], //修改vue获取变量的方式
        "data":{  //数据
            "message": "123"
        },
        method:{}
    })
</script>
</html>

3.4 常用的基本语法
3.4.1 插值操作

插值操作就是将Vue对象中的数据显示到页面上。

<div id="content">
    [[message]]
</div>
</body>
<script>
    new Vue({
        "el": "#content",
        "delimiters": ["[[","]]"],
        "data":{
            "message": "123"
        }
    })
</script>
3.4.2 v-bind

属性绑定,如果属性值需要字符串和变量拼接后得到时,字符串要加上引号,如下面a标签的href属性,若拼接不正确会导致页面渲染失败。

<div id="content">
    <p v-bind:style="color">123</p>
	<a v-bind:href="'/buyer/goods_detail?goods_id='+[[ goods_id ]]">
</div>
</body>
<script>
    new Vue({
        "el": "#content",
        "delimiters": ["[[","]]"],
        "data":{
            "color": "color:red",
            "goods_id": 1
        }
    })
</script>
3.4.3 v-if

指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true值的时候被渲染。

<div id="content">
    <p v-if="age > 18">成年了</p>
</div>
</body>
<script>
    new Vue({
        "el": "#content",
        "delimiters": ["[[","]]"],
        "data":{
            "age": 20
        }
    })
</script>
3.4.4 v-for

循环展示数据

<div id="content">
	<p v-for="i in list">[[ i ]]</p>
</div>
</body>
<script>
    new Vue({
        "el": "#content",
        "delimiters": ["[[","]]"],
        "data":{
            "list": ['1','2','3']
        }
    })
</script>
3.4.5 v-on

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

<div id="content">
    <input type="button" value="点击" v-on:click="my_test()">
</div>
</body>
<script>
    new Vue({
        "el": "#content",
        "delimiters": ["[[","]]"],
        "data":{
        },
        methods:{
            my_test: function () {
                console.log(1)
                alert("点击事件")
            }
        }
    })
</script>

示例:

<div id="content">

    [[message]]

    <p v-bind:style="color">123</p>

    <p v-if="age > 18">成年了</p>

    <p v-for="i in list">[[ i ]]</p>

    <input type="button" value="点击" v-on:click="my_test">
</div>
</body>
<script>
    new Vue({
        "el": "#content",
        "delimiters": ["[[","]]"],
        "data":{
            "message": "123",
            "color": "color:red",
            "age": 20,
            "list": ['1','2','3']
        },
        methods:{
            my_test: function () {
                console.log(1)
                alert("点击事件")
            }
        }
    })
</script>

3.5 异步请求

有时候我们需要发送异步请求来获取并渲染数据,vue-resource提供了这个功能,它不仅可以便捷的给dom绑定数据,还可以发送多个异步请求。

3.5.1 导包

参考3.1

3.5.2 基本格式
// this.$http 固定写法
// this.$http.请求方法 比如get、post
// this.$http.请求方法(url) url:异步请求的路由

this.$http.get("/api/get_goods_list_info/?goods_type=1").then(
    function (data) { // 请求成功执行的函数,data是服务器返回的数据
        console.log(data)
        this.goods_list = data.data.goods_page_list
        this.page_range = data.data.page_range
    },function (error) {  // 请求失败执行的函数
        console.log(error)
    }
)

如果需要传递数据,可以使用 this.$http.get(url,{params : jsonData}) 格式,第二个参数jsonData 就是传到后端的数据。post 发送数据到后端,需要第三个参数 {emulateJSON:true}。

this.$http.get("/api/get_goods_list_info/",{"params":{"goods_type":1}}).then(
    function (data) { // 请求成功执行的函数,data是服务器返回的数据
        console.log(data)
        this.goods_list = data.data.goods_page_list
        this.page_range = data.data.page_range
    },function (error) {  // 请求失败执行的函数
        console.log(error)
    }
)

案例:vue获取商品列表页数据

视图函数

def get_goods_list_info(request):
    goods_type_id = request.GET.get("goods_type")
    goods_type = GoodsType.objects.get(id=goods_type_id)
    goods_list = goods_type.goods_set.all().order_by("id")
    page_num = int(request.GET.get("page", 1))  # 获取页数
    page_size = 4  # 每一页展示的数据
    paginator = Paginator(goods_list, page_size)  # 创建分页对象
    page = paginator.page(page_num)  # 根据页数返回当页的数据
    page_range = page.paginator.page_range  # 返回range对象,分页的数量
    if page_num <= 2:
        my_page_range = page_range[:5]
    else:
        my_page_range = page_range[page_num - 3: page_num + 2]
    goods_page_list = [
        {"id": goods.id, "picture": goods.picture.name, "name": goods.name, "price": goods.price, "unite": goods.unite}
        for goods in page]
    result = {
        "goods_page_list": goods_page_list,
        "page_range": [i for i in my_page_range]
    }
    return JsonResponse(result, safe=False, json_dumps_params={"ensure_ascii": False})

前端

<div class="col-xs-12 col-sm-10">
    <div class="panel panel-success">
        <!-- 商品列表 -->
        <div class="panel-body">
            <div class="col-xs-12 col-sm-3" v-for="goods in goods_list">
                <a v-bind:href="'/buyer/goods_detail?goods_id='+[[ goods.id ]]" class="thumbnail">
                    <img v-bind:src="'/static/'+[[ goods.picture ]]" class="img-responsive">
                </a>
                <p class="text-center">[[ goods.name ]]</p>
                <p class="text-center myps"><span>¥[[ goods.price ]]</span><span>[[ goods.price ]]/[[ goods.unite ]]</span><span><img src="/static/buyer/images/carts.png"/></span></p>
            </div>
        </div>
    </div>
    <!-- 分页 -->
    <div class="col-xs-12 col-sm-8 col-sm-offset-4">
        <ul class="pagination col-xs-12 col-sm-8 col-sm-offset-2">
            <li class="page-item" v-for="page in page_range">
                <a class="page-link" v-on:click="get_page([[page]])">[[page]]</a>
            </li>
        </ul>
    </div>
</div>
<script src="/static/buyer/js/vue.min.js"></script>
<script src="/static/buyer/js/vue-resource.min.js"></script>
<script>
    var now_url = window.location.href  // 获取当前页面url
    var goods_type = now_url.split("?")[1].split("=")[1]  // 获取路由上的goods_type信息
    new Vue({
        el: "#content",
        delimiters: ["[[","]]"],
        data: {
            goods_list: [],
            two_goods:[],
            page_range:[]
        },
        methods: {
            get_goods_list_info: function () {
                this.$http.get("/api/get_goods_list_info/?goods_type="+goods_type).then(
                    function (data) {
                        console.log(data)
                        this.goods_list = data.data.goods_page_list
                        this.page_range = data.data.page_range
                    },function (error) {
                        console.log(error)
                    }
                )
            },
            get_page:function (e) {
                var page = e[0][0]
                console.log(page)
                url = "/api/get_goods_list_info/?goods_type="+goods_type+"&page="+page
                console.log(url)
                this.$http.get(url).then(
                    function (data) {
                        console.log(data)
                        this.goods_list = data.data.goods_page_list
                        this.page_range = data.data.page_range
                    },function (error) {
                        console.log(error)
                    }
                )
            }
        },
        mounted: function () {  //相当于js onload表示窗体加载完毕
            this.get_goods_list_info()
        },
    })
</script>

结果:

4、REST

REST(Representational State Transfer的简称,中文翻译为“表现层状态转移”)与技术无关,是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。满足这些约束条件和原则的应用程序或设计就是 RESTful。
REST需要遵循如下10条规则:

1、协议

API与用户的通信协议,总是使用HTTPS协议。

2、域名

在域名上进行区分,例如

子域名方式:

www.baidu.com 所有人都知道这是访问网站

api.baidu.com 看到这个网站就就知道返回json、xml数据。

Url上区分:

www.baidu.com/

www.baidu.com/api/ (添加一个api 目录,让人一看到就知道是一个接口)

3、版本

因为项目存在着版本迭代更新,因此建议在url上添加版本

www.baidu.com/api/v1/

http://www.example.com/app/1.0/foo

v1、1.0: 就是代表第一版。

4、路径

网络上任何东西都是资源,均使用名词表示(可复数)

通俗来说,URL不应该使用动作来描述。例如,下面是一些不符合统一接口 要求的URI: GET:/getUser/1、 POST:/createUser、PUT:/updateUser/1 、DELETE:/deleteUser/1,建议使用 /user/1

5、HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面四个(括号里是对应的SQL命令)。

GET(SELECT):从服务器取出资源(一项或多项)。

POST(CREATE):在服务器新建一个资源。

PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

DELETE(DELETE):从服务器删除资源。

还有三个不常用的HTTP动词。

PATCH(UPDATE):在服务器更新(更新)资源(客户端提供改变的属性)。

HEAD:获取资源的元数据。

OPTIONS:获取信息,关于资源的哪些属性是客户端可以访问改变的。

下面是一些例子。

GET /zoos:列出所有动物园

POST /zoos:新建一个动物园(上传文件)

GET /zoos/ID:获取某个指定动物园的信息

PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)

PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)

DELETE /zoos/ID:删除某个动物园

GET /zoos/ID/animals:列出某个指定动物园的所有动物

DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

6、过滤信息

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。

?limit=10:指定返回记录的数量

?offset=10:指定返回记录的开始位置。

?page=2&per_page=100:指定第几页,以及每页的记录数。

?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。

?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如:

GET /zoos/ID/animals

GET /animals?zoo_id=ID

二者含义是相同的

7、状态码

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

200 OK - [GET]:服务器成功返回用户请求的数据

201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。

202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)

204 NO CONTENT - [DELETE]:用户删除数据成功。

400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作

401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。

403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。

404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。

406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。

410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。

422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。

500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

8、错误处理

如果状态码是4xx,服务器就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。{error: “Invalid API key”}

9、返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

GET /collection:返回资源对象的列表(数组)

GET /collection/resource:返回单个资源对象

POST /collection:返回新生成的资源对象

PUT /collection/resource:返回完整的资源对象

PATCH /collection/resource:返回完整的资源对象

DELETE /collection/resource:返回一个空文档

10、超媒体

RESTful API最好做到Hypermedia(即返回结果中提供链接,连向其他API方法),使得用户不查文档,也知道下一步应该做什么。

比如,Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。
{
“current_user_url”: “https://api.github.com/user”,

“authorizations_url”: “https://api.github.com/authorizations”,

// …

}
从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。
{

​ “message”: “Requires authentication”,

“documentation_url”: “https://developer.github.com/v3”

}
上面代码表示,服务器给出了提示信息,以及文档的网址。

11、其他

服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

5、FBV和CBV

Django中关于视图有两种写法:基于函数的视图(FBV)和基于类的视图(CBV),function base view 函数式class base view 类式

5.1 FBV

函数至少有一个参数,一般名字是request,表示当前请求对象。

5.1.1 csrf

后端工程师做接口开发测试的时候用前端发送请求太过麻烦,为了解决这个问题可以使用postman工具直接发送各种请求,Django除了get请求其他请求都会进行csrf拦截,为了方便开发,测试的时候都会把csrf关闭。

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt  # 被装饰的函数不会被cstf拦截
def fvb(request):
    pass
5.1.2 示例

视图

@csrf_exempt
def fvb(request):
    if request.method == "GET":
        return HttpResponse("GET...")
    elif request.method == "POST":
        return HttpResponse("POST...")
    elif request.method == "PUT":
        return HttpResponse("PUT...")
    elif request.method == "DELETE":
        return HttpResponse("DELETE...")

路由

path("api/fvb/", fvb)

5.2 CBV

视图类必须直接或者间接继承django.views.View类,定义方法表示接受对应的请求。方法中request表示请求对象,*args和**kwargs用来接收。

5.2.1 csrf
from django.views.decorators.csrf import csrf_exempt

@method_decorator(csrf_exempt, "dispatch")  # 所有请求方法的入口在dispatch这里,装饰这个方法即不会被cstf拦截
class CBV(View):
    def get(self, request, *args, **kwargs):
        pass
5.2.2 示例

视图

@method_decorator(csrf_exempt, "dispatch")
class CBV(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("GET...")

    def post(self, request, *args, **kwargs):
        return HttpResponse("POST...")

    def put(self, request, *args, **kwargs):
        return HttpResponse("PUT...")

    def delete(self, request, *args, **kwargs):
        return HttpResponse("DELETE...")

路由

path("api/cbv/", CBV.as_view())

6、Django REST Framework 框架

自己写REST接口太复杂,因为规范很多,Django拥有丰富的插件,有一个关于REST的插件,使用起来比较方便。文档:https://www.django-rest-framework.org/

6.1 安装DRF框架
6.1.1 安装
pip install djangorestframework
6.1.2 app安装

6.2 使用

DRF中的序列化类可以进行数据格式的转换,例如将Python中的字典转换成JSON数据格式。json序列化:实体类(或字典)与json格式字符串转换。

6.2.1 步骤

1、创建Serializer类

在应用当中创建serializers文件用来编写序列化类

需要继承 ModelSerializer或HyperlinkedModelSerializer,后者会生成url路由。

from rest_framework import serializers
from store.models import Goods


class GoodsSerializers(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = "__all__"
        # 也可以自定义字段
        # fields = ["name", "price", "goodstype"]

# meta属性解释:
# model:对应的model类
# fields:model类要序列化的属性 “__all__” 表示所有属性
# depth:关联对象序列化的深度,默认只序列化关联对象的id,设置为1后序列化关联对象所有filelds属性

2、创建视图

from rest_framework import viewsets
from .serializers import GoodsSerializers

class GoodsViewSet(viewsets.ModelViewSet):
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializers

    def get_serializer_context(self):
        """不对字段进行处理,返回原来的数据"""
        return {"view": self}

3、指出路由

# 创建DRF相关的路由
from django.urls import path, re_path
from rest_framework.routers import DefaultRouter
from api.views import GoodsViewSet

urlpatterns = [
    path("test/", test)
]

router = DefaultRouter()
router.register("ser_goods", GoodsViewSet)
urlpatterns += router.urls

4、简单的分页

接口直接返回所有数据是不合适的,并且数据量太大的时候容易发生问题,所以可以使用分页来解决这个问题。DRF提供了快速的分页策略,只需要在settings当中进行配置就可以了。

6.2.2 测试

get:获取所有

get:分页获取

get:获取单个

post:新增

put:修改

delete:删除

6.3 视图类
6.3.1 继承APIView类

APIView 对Django中的django.views.View类进行了进一步封装,功能更加强大。但是不能使用DRF的分页

# serializers.py
class GoodsSerializers(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = "__all__"
# views.py
from rest_framework.views import APIView
from .serializers import GoodsSerializers

class SeleteGoodsByType(APIView):
    """根据商品类型查询所有商品"""

    def get(self, request, *args, **kwargs):
        """接收GET请求"""
        # 接收参数
        goodstype_id = request.GET.get("goodstype_id")
        # 查询数据
        goods_qs = Goods.objects.filter(goodstype_id=goodstype_id).order_by("-id")
        # 序列化
        serializer = GoodsSerializers(goods_qs, many=True)
        # safe: 默认只支持返回字典类型数据,设置为false可以返回其他类型数据
        # json_dumps_params:设置是否转换成ASCII编码,不转则为中文
        return JsonResponse(serializer.data, safe=False, json_dumps_params={"ensure_ascii": False})
# urls.py
from api.views import SeleteGoodsByType

urlpatterns = [
    path("goods/", SeleteGoodsByType.as_view()),
]

6.3.2 使用mixins类(常用)

使用REST框架的mixins类,可以提高代码的重用率,使用OPP中的继承。

class CreateModelMixin(object): 增加

class ListModelMixin(object): 展示数据列表

class RetrieveModelMixin(object): 展示单条数据

class UpdateModelMixin(object): 更新单条数据

class DestroyModelMixin(object): 删除单条数据

# serializers.py
class GoodsSerializers(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = "__all__"
# views.py
from rest_framework import generics
from rest_framework import mixins


class SeleteGoodsByType2(generics.GenericAPIView,
                         mixins.ListModelMixin,
                         mixins.DestroyModelMixin,
                         mixins.RetrieveModelMixin,
                         mixins.UpdateModelMixin,
                         mixins.CreateModelMixin
                         ):
    """获取指定商品类型下的商品"""
    # 序列化类
    serializer_class = GoodsSerializers

    def get_queryset(self):
        """根据类型id查询并返回结果集"""
        goodstype_id = self.request.GET.get("goodstype_id")
        if goodstype_id:
            goods_qs = Goods.objects.filter(goodstype_id=goodstype_id).order_by("-id")
        else:
            goods_qs = Goods.objects.all()
        return goods_qs

    def get(self, request, *args, **kwargs):
        """get请求,获取参数查询数据"""
        pk = kwargs.get("pk")  # 获取get请求的参数
        if pk:
            # 返回单个数据
            return self.retrieve(request, *args, **kwargs)
        else:
            # 返回查询集合
            return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        """post请求,数据的添加"""
        print("request.method:", request.method)  # 获取请求的方法
        print("request.POST", request.POST)  # 获取post发送过来的数据
        print("args, kwargs:", args, kwargs)  # 路由上的参数
        return self.create(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        """put请求,数据的修改"""
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        """delete请求,数据的删除"""
        return self.destroy(request, *args, **kwargs)

    def get_serializer_context(self):
        """不进行字符串拼接,返回原来的数据"""
        return {"view": self}
form api.views import SeleteGoodsByType2

urlpatterns = [
    path("goods2/", SeleteGoodsByType2.as_view()),
    re_path(r"goods2/(?P<pk>\d+)$", SeleteGoodsByType2.as_view()),
]

测试

GET:

1、根据商品类型和id查询单个数据

2、根据商品类型查询对应类型的数据(可以分页)

POST:

添加数据

PUT:

更新id为18的商品的数量

DELETE:

删除id为20的商品的数量

6.3.3 通用视图类

mixins类视图的简化
使用mixin类,我们重写了视图,使用的代码比以前略少,但我们可以更进一步。REST框架提供了一组已经混合的通用视图,我们可以使用它来进一步减少我们的views.py模块。

# serializers.py
class GoodsSerializers(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = "__all__"

通过查看ListAPIView可以看出,该视图即是查询集合的视图。

# ListAPIView视图源码
class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

继承该类后开发者只需自定义查询集合语句返回query_set对象即可获取数据集合,无需再写获取集合数据的函数。

# views.py
from rest_framework import generics

class SeleteGoodsByType3(generics.ListAPIView):
    """获取指定商品类型下的商品"""
    # 序列化类
    serializer_class = GoodsSerializers

    def get_queryset(self):
        """根据类型id查询并返回结果集"""
        goodstype_id = self.request.GET.get("goodstype_id")
        if goodstype_id:
            goods_qs = Goods.objects.filter(goodstype_id=goodstype_id).order_by("-id")
        else:
            goods_qs = Goods.objects.all()
        return goods_qs

    def get_serializer_context(self):
        """不进行字符串拼接,返回原来的数据"""
        return {"view": self}
form api.views import SeleteGoodsByType2

urlpatterns = [
    path(r"goods3/", SeleteGoodsByType3.as_view()),
]

测试

获取商品类型为1的所有商品

REST还提供了很多混合的通用视图,可查看源码继承使用,例如CreateAPIView(数据添加视图)、RetrieveAPIView(查询单个数据视图)等等。虽然这种方法减少了代码量,但在某些特殊需求下不够灵活,只适用于一般业务逻辑的操作。

### 回答1: 你可以回答这个问题。django-vue-admin 是一个基于 Django 和 Vue.js 的全栈开发框架,可以快速搭建后台管理系统。它提供了丰富的组件和插件,可以帮助开发者快速构建出美观、易用的管理界面。 ### 回答2: django-vue-admin是一个基于Django和Vue.js开发的开源管理系统框架,旨在帮助开发者快速构建和定制现代化的管理系统。它采用前后端分离的架构,后端使用Django提供API接口,前端使用Vue.js进行展示和交互。 使用django-vue-admin,开发者可以快速搭建一个具备基本功能的管理系统。框架提供了一套完整的通用模型和视图,开发者只需根据自己的需求进行配置和扩展即可实现快速开发。同时,它采用了模块化和组件化的设计,开发者可以方便地替换和定制界面的各个组件,实现个性化的界面展示。 django-vue-admin还提供了丰富的功能模块,如用户管理、权限管理、角色管理、菜单管理等,开发者可以根据项目需要进行选择和集成。框架还支持多语言和多主题的配置,方便开发者根据不同用户需求进行界面定制。 此外,django-vue-admin还面向中小型项目进行了性能优化,采用了异步加载、缓存和CDN加速等技术,提高了系统的响应速度和用户体验。 总的来说,django-vue-admin是一个强大而灵活的管理系统开发框架,它简化了开发者的开发流程,提高了开发效率。无论是快速搭建简单的管理系统,还是进行个性化的定制开发,都可以选择django-vue-admin作为开发工具。 ### 回答3: django-vue-admin 是一个用于快速开发后台管理系统的开源项目。它的主要特点是结合了 Django 和 Vue.js 框架的优势,使开发者能够高效地创建功能完善、界面友好的管理系统。 django-vue-admin 提供了一套基础的后台管理功能,包括用户管理、角色管理、权限管理、日志管理等。开发者可以根据自己的需求进行功能定制和扩展。 django-vue-admin 的前端使用了 Vue.js 框架,通过组件化的方式构建用户界面,并且使用了 Element-UI 组件库来提供丰富的UI组件。这使得开发者能够快速搭建出现代化、响应式的管理系统界面。后端则使用了 Django 框架,提供了强大的数据处理和权限控制能力。 在开发上,django-vue-admin 使用了前后端分离的架构,前端和后端通过 API 进行通信。这使得开发者可以独立地进行前后端开发,提高了开发效率和团队协作能力。同时,由于前后端分离的优势,django-vue-admin 的性能也得到了明显的提升。 总之,django-vue-admin 是一个功能强大、易用、高效的后台管理系统开发框架。它能够帮助开发者快速开发出现代化的后台管理系统,并且具备良好的扩展能力。无论是个人开发者还是企业开发团队,都可以利用 django-vue-admin 来构建稳定、高效的管理系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值