zoukankan      html  css  js  c++  java
  • python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾

    1. 内容回顾
        1. VueX
                        VueX分三部分
        1. state         2. mutations         3. actions
        存放数据       修改数据的唯一方式        异步操作
        
        修改state中数据的步骤:
        1. 页面上交互 触发数据的变化
        2. 去后端获取新的数据(异步操作 ajax请求)
        3. dispatch('获取新数据')                                       --> 放在actions中
        4. 拿到了新数据了
        5. 去更新state中对应的数据(同步操作 state.noteList=[xx,xx,xx])--> 放在mutations中
    
    添加新笔记
        1. 把新的笔记数据发送到后端
            dispatch('添加新笔记数据')       --> dispatch('重新拉取笔记数据')
                 --> commit('大仓库添加笔记')
    View Code

    举例:

    新建一个项目mysite,修改urls.py,增加路径

    from app01 import views
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('index/', views.index),
        path('ajax_test/', views.ajax_test),
    ]
    View Code

    修改views.py,增加视图函数

    from django.shortcuts import render
    from django.http import JsonResponse
    
    # Create your views here.
    def index(request):
        return render(request,"index.html")
    
    def ajax_test(request):
        return JsonResponse({"code":0})
    View Code

    增加index.html,注意:ajax的路径是故意写错的

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <button id="b1">点我</button>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        function sendAjax() {  //发送ajax请求
            $.ajax({
                    url: '/ajax_123/',
                    type: 'get',
                    success: function (res) {
                        console.log('成功咯!');
                        console.log(res);
                    },
                    error:function (err) {
                        console.log('出错啦!');
                        console.log(err);
                    }
                })
        };
    
        $('#b1').click(function () {
            var ret = sendAjax();  //执行方法
            console.log(ret);
        });
    </script>
    </body>
    </html>
    View Code

    启动django项目,访问首页,点击按钮

    发现ret的值为undefined,执行sendAjax方法时,无法知道异步请求的状态是成功还是失败

    修改为正确的url,改为ajax_test

    刷新页面,再次点击

    发现ret的值还是为undefined,为什么呢?因为ajax是异步请求。ret不会等待ajax请求完毕,就直接执行下面一行,所以输出undefined。

    所以说,ajax不能向上面那样封装函数!如果不封装函数,代码有可能是这样的

    $.ajax({
        url: '/ajax_123/',
        type: 'get',
        success: function (res) {
           $.ajax({
                url: '/ajax_456/',
                type: 'get',
                success: function (res) {
                   ...
                },
                error:function (err) {
                    ...
                }
            })
        },
        error:function (err) {
            ...
        }
    })
    View Code

    代码太冗长了,必须要封装函数。

    针对不能获取值的问题,使用Promise,就可以解决!

    一、Promise

    Promise,他是一个对象,是用来处理异步操作的,可以让我们写异步调用的时候写起来更加优雅,更加美观便于阅读。顾名思义为承诺、许诺的意思,意思是使用了Promise之后他肯定会给我们答复,无论成功或者失败都会给我们一个答复,所以我们就不用担心他跑了哈哈。所以,Promise有三种状态:pending(进行中),resolved(完成),rejected(失败)。只有异步返回的结构可以改变其状态。所以,promise的过程一般只有两种:pending->resolved或者pending->rejected。

    promise对象还有一个比较常用的then方法,用来执行回调函数,then方法接受两个参数,第一个是成功的resolved的回调,另一个是失败rejected的回调,第二个失败的回调参数可选。并且then方法里也可以返回promise对象,这样就可以链式调用了。接下来上代码:

    修改index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <button id="b1">点我</button>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        function sendAjax(arg) {
            return new Promise(function (resolve, reject) {
                $.ajax({
                    url: arg,
                    type: 'get',
                    success: function (res) {
                        console.log("成功咯");
                        resolve(res)
                    },
                    error:function (err) {
                        console.log("出错啦");
                        reject(err)
                    }
                })
            })
        };
    
        $('#b1').click(function () {
            //执行方法,指定url为/ajax_test/
            var ret = sendAjax('/ajax_test/');
            ret.then(function (value) {  //成功时,执行
                console.log(value);
            }).catch(function (err) {   //失败时,执行
                console.log(err)
            });
        })
    </script>
    </body>
    </html>
    View Code

    上边代码中,定义了一个ret变量,然后执行sendAjax函数,函数返回一个Promise对象,然后对象里边接收一个匿名函数,分别把resolve跟reject方法当参数传进去,用ajax来模拟异步请求

    当执行resolve方法后就会调用then方法的一个函数。结果如下:

    这样的话,就可以指定ajax异步请求的状态是成功还是失败。

    在小程序应用中,会大量应用到Promise。

    如果想往前端方向发展,有一个面试题,手写一个promise。当然不是上面的代码,而是写底层原理!

    二、箭头函数

    箭头函数就是个简写形式的函数表达式,并且它拥有词法作用域的this值(即不会新产生自己作用域下的this,arguments,super和new.target等对象)。此外,箭头函数总是匿名的。

    基础语法

    (param1, param2, …, paramN) => { statements }
    (param1, param2, …, paramN) => expression
             // equivalent to:  => { return expression; }
     
    // 如果只有一个参数,圆括号是可选的:
    (singleParam) => { statements }
    singleParam => { statements }
     
    // 无参数的函数需要使用圆括号:
    () => { statements }

    each() 

    each() 方法为每个匹配元素规定要运行的函数。

    提示:返回 false 可用于及早停止循环。

    语法

    $(selector).each(function(index,element))

    举例:打印this

    修改index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <button id="b1">点我</button><br/>
    <hr>
    <div>div1</div>
    <div>div2</div>
    <div>div3</div>
    
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        $('#b1').click(function () {
            console.log(this);  //this指的是button
            $("div").each(function () {  //循环遍历div
                console.log(this);  //this指的是div
            })
        })
    </script>
    </body>
    </html>
    View Code

    刷新网页,点击按钮,查看console

    注意:这2个this是不一样的。上面的this是butthon,下面的this是div

    一般请求下,如果想让$("div").each(function () {...}这里面的代码获取到button按钮,

    需要在上层定义个变量_this=$(this),然后下面调用_this就可以了。

    但是这样做比较麻烦,使用箭头函数,就可以解决

    将匿名函数改成箭头函数

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <button id="b1">点我</button><br/>
    <hr>
    <div>div1</div>
    <div>div2</div>
    <div>div3</div>
    
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        $('#b1').click(function () {
            console.log(this);  //this指的是button
            $("div").each(()=> {  //循环遍历div
                console.log(this);
            })
        })
    </script>
    </body>
    </html>
    View Code

    刷新网页,重新点击,效果如下:

    总结:

    想要内层的this和外层的this一样,使用箭头函数,就可以实现!将匿名函数换成箭头函数

    FBV

    FBV(function base views) 就是在视图里使用函数处理请求。

    看代码:

    views.py

    def index(request):
        if request.method == "POST":
            print(request.POST)
            # 修改数据库
            return JsonResponse("OK")
        return render(request, "index.html")
    
    def index2(request):
        if request.method == "GET":
            return render(request, "index.html")
    
        print(request.POST)
        # 修改数据库
        return JsonResponse("OK")
    View Code

    上面就是FBV的使用。

    这2个视图函数,都是实现同样的功能!

    那么问题来了,哪个更好一点呢?

    答案是第一种,为什么呢?在我们的现有的理念里面,只知道GET和POST。所以这2个视图函数,是没有任何区别的。

    但是如果一旦上线,对于个人用户,它可以发送其他类型的,比如PUT。那么线上就会报错!

    所以:对于比较重大的操作,比如修改数据库,使用if单独判断请求类型!

    那么我们推荐使用第一种方式!

    如果想使用第二种方式,则需要使用if分支判断,这样更严谨一点。

    def index2(request):
        if request.method == "GET":
            return render(request, "index.html")
        elif request.method == "POST":
            print(request.POST)
            # 修改数据库
            return JsonResponse("OK")
    View Code

    CBV

    CBV(class base views) 就是在视图里使用类处理请求。

    将上述代码中的views.py 修改为如下:

    from django import views
    
    class index(views.View):
        def get(self,request):
            return render(request, "index.html")
    
        def post(self,request):
            print(request.POST)
            # 修改数据库
            return JsonResponse("OK")
    View Code

    注意事项:
    1. CBV定义一定要继承django.views.View
    2. 注册路由的时候要写 类名.as_view()
    3. 具体原理是:dispatch()方法 中 利用反射 找到 每个请求要执行的方法

    更多详细介绍,请参考链接:

    https://www.cnblogs.com/xiao987334176/p/9330368.html#autoid-3-4-0

    三、Django REST framework

    django-rest-framework是一个功能强大且灵活的工具包,用于构建Web API。

    您可能希望使用REST框架的一些原因:

    官方网址:

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

    中文文档:

    https://q1mi.github.io/Django-REST-framework-documentation/

    上面说了那么多的 RESTful API,其实是为了引出django-rest-framework。它就是专门用来写API接口的!

    一般应用是前后端分离的

    前端:

    APP、PC网站、手机网页、手机APP、ipad平板

    后端:提供API,返回 JSON格式的数据,就能支撑前端的5种业务!

    Web API

    官方定义如下,强调两个关键点,即可以对接各种客户端(浏览器,移动设备),构建http服务的框架。

    为什么要用 Web API

    Web API最重要的是可以构建面向各种客户端的服务。另外与WCF REST Service不同在于,Web API利用Http协议的各个方面来表达服务(例如 URI/request response header/caching/versioning/content format),因此就省掉很多配置。

    安装Django rest framework

    pip install djangorestframework

    提示以下信息,表示安装成功

    Installing collected packages: djangorestframework
    Successfully installed djangorestframework-3.8.2

    四、生成json数据三种方式

    准备工作

    安装虚拟环境

    在公司开发,一般使用虚拟环境,虚拟环境的安装,请参考链接:

    https://www.cnblogs.com/xiao987334176/p/9330368.html#autoid-5-3-0

    安装虚拟环境之后,安装django,指定版本为1.11.11

    pip安装包临时指定 从国内的清华pip源下载:

    pip install django==1.11.11 -i https://pypi.tuna.tsinghua.edu.cn/simple

    将虚拟环境的依赖包关系导出到requirements.txt

    pip freeze > requirements.txt

    注意:约定成熟使用requirements.txt,一些开源的django项目,里面一般使用这个名字!

    查看requirements.txt文件,内容如下:

    Django==1.11.11
    pytz==2018.5

    如果需要按照 requirements.txt 安装项目依赖的第三方包,使用命令:

    pip install -r requirements.txt

    新建一个虚拟环境,测试一下,就可以了!

    新建项目about_drf

    新建项目时,指定虚拟环境,使用django 1.11.11

    修改models.py,增加表

    from django.db import models
    
    # Create your models here.
    
    
    # 文章表
    class Article(models.Model):
        title = models.CharField(max_length=32)
        # 文章发布时间
        # auto_now每次更新的时候会把当前时间保存
        create_time = models.DateField(auto_now_add=True)
        # auto_now_add 第一次创建的时候把当前时间保存
        update_time = models.DateField(auto_now=True)
        # 文章的类型
        type = models.SmallIntegerField(
            choices=((1, "原创"), (2, "转载")),
            default=1
        )
        # 来源
        school = models.ForeignKey(to='School', on_delete=models.CASCADE)
        # 标签
        tag = models.ManyToManyField(to='Tag')
    
    
    # 文章来源表
    class School(models.Model):
        name = models.CharField(max_length=16)
    
    
    # 文章标签表
    class Tag(models.Model):
        name = models.CharField(max_length=16)
    View Code

    说明:

    SmallIntegerField 
    小整数字段,类似于IntegerField,取值范围依赖于数据库特性,[-32768 ,32767]的取值范围对Django所支持的数据库都是安全的

    SmallIntegerField长度是5位,IntegerField长度是10位

    choices

    用于页面上的选择框标签,需要先提供一个二维的二元元组,第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体内容。在浏览器页面上将显示第二个元素的值

    auto_now_add和auto_now,对于一个字段而言,不能同时写,只能有一个!

    on_delete=models.CASCADE 表示级联删除。也就是说,有关系的记录,会一并删除!

    ManyToManyField 表示多对多,它会自动创建关系表

    使用2个命令,生成表

    python manage.py makemigrations
    python manage.py migrate

    使用navicat打开sqlite3数据库

    增加表数据

    执行以下sql语句

    # 标签表
    INSERT INTO app01_tag ("id", "name") VALUES (1, 'Python');
    INSERT INTO app01_tag ("id", "name") VALUES (2, 'Django');
    INSERT INTO app01_tag ("id", "name") VALUES (3, 'Vue');
    
    # 校区表
    INSERT INTO app01_school ("id", "name") VALUES (1, '北京校区');
    INSERT INTO app01_school ("id", "name") VALUES (2, '上海校区');
    INSERT INTO app01_school ("id", "name") VALUES (3, '深圳校区');
    
    # 文章表
    INSERT INTO app01_article ("id", "title", "create_time", "type", "school_id", "update_time") VALUES (1, 'Python三年用不上', '2018-07-31', 1, 1, '2018-07-31');
    INSERT INTO app01_article ("id", "title", "create_time", "type", "school_id", "update_time") VALUES (2, '你不可能知道Vue有多简单!', '2018-07-31', 2, 2, '2018-07-31');
    INSERT INTO app01_article ("id", "title", "create_time", "type", "school_id", "update_time") VALUES (3, 'MySQL一点都不难', '2018-07-31', 1, 3, '2018-07-31');
    
    # 文章和标签关系表
    INSERT INTO app01_article_tag ("id", "article_id", "tag_id") VALUES (1, 1, 1);
    INSERT INTO app01_article_tag ("id", "article_id", "tag_id") VALUES (2, 1, 2);
    View Code

    json支持7种数据格式

    python 原始类型向 json 类型的转化对照表:

    Python JSON
    dict object
    list, tuple array
    str, unicode string
    int, long, float number
    True true
    False false
    None null

    日期转化为字符串

    在项目根目录下,创建文件date_trans.py

    import datetime
    
    # 获取当前时间
    now = datetime.datetime.now()
    print(now, type(now))
    
    #格式化时间,格式为年-月-日
    format_time = now.strftime('%Y-%m-%d')
    print(format_time, type(format_time))
    View Code

    执行输出:

    2018-07-31 19:07:47.346727 <class 'datetime.datetime'>
    2018-07-31 <class 'str'>

    可以发现,格式化之后,数据类型为字符串

    第一个版本:使用json

    修改urls.py,增加路径

    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^article_list/', views.article_list),
    ]
    View Code

    修改views.py,增加视图函数

    from django.shortcuts import render,HttpResponse
    from django.http import JsonResponse
    from app01 import models
    import json
    
    # Create your views here.
    
    def article_list(request):
        # 去数据库查询所有的文章数据
        query_set = models.Article.objects.all().values("id", "title", "create_time", "type", "school__name")
        # 序列化成json格式
        # 1. 先把时间对象转换成字符串格式
        for i in query_set:
            i["create_time"] = i["create_time"].strftime('%Y-%m-%d')
    
        data = json.dumps(list(query_set), ensure_ascii=False)
        # 返回
        return HttpResponse(data)
    View Code

    注意:json只支持7种数据类型,ORM查询出来的结果为QuerySet类型,它是不支持的。

    日期对象也是不支持的,需要转化为字符串。

    启动django项目,访问url: http://127.0.0.1:8000/article_list/

    页面输出:

    [{"create_time": "2018-07-31", "school__name": "北京校区", "id": 1, "type": 1, "title": "Python三年用不上"}, {"create_time": "2018-07-31", "school__name": "上海校区", "id": 2, "type": 2, "title": "你不可能知道Vue有多简单!"}, {"create_time": "2018-07-31", "school__name": "深圳校区", "id": 3, "type": 1, "title": "MySQL一点都不难"}]
    View Code

    每一个时间,都要转换为字符串,太麻烦了。

    第二个版本:JsonResponse

    JsonResponse 对象:

    class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None,**kwargs)

    这个类是HttpRespon的子类,它主要和父类的区别在于:

    • 1.它的默认Content-Type 被设置为: application/json
    • 2.第一个参数,data应该是一个字典类型,当 safe 这个参数被设置为:False ,那data可以填入任何能被转换为JSON格式的对象,比如list, tuple, set。 默认的safe 参数是 True. 如果你传入的data数据类型不是字典类型,那么它就会抛出 TypeError的异常
    • 3.json_dumps_params参数是一个字典,它将调用json.dumps()方法并将字典中的参数传入给该方法。
    from django.shortcuts import render,HttpResponse
    from django.http import JsonResponse
    from app01 import models
    import json
    
    # Create your views here.
    
    def article_list(request):
        # 去数据库查询所有的文章数据,返回queryset,每一个元素都是字典
        query_set = models.Article.objects.all().values("id", "title", "create_time", "type", "school")
        print(query_set)
        for i in query_set:
            print(i)
            # 学校对象
            school_obj = models.School.objects.filter(id=i['school']).first()
            # 学校id
            id = school_obj.id
            # 学校的名字
            name = school_obj.name
            # 修改字典,key为school的值
            i["school"] = {"id": id, "name": name}
    
        # 返回json对象,safe=False表示填入任何能被转换为JSON格式的对象
        return JsonResponse(list(query_set), safe=False)
    View Code

    刷新网页,页面输出:

    [{"title": "Pythonu4e09u5e74u7528u4e0du4e0a", "type": 1, "create_time": "2018-07-31", "school": {"name": "u5317u4eacu6821u533a", "id": 1}, "id": 1}, {"title": "u4f60u4e0du53efu80fdu77e5u9053Vueu6709u591au7b80u5355uff01", "type": 2, "create_time": "2018-07-31", "school": {"name": "u4e0au6d77u6821u533a", "id": 2}, "id": 2}, {"title": "MySQLu4e00u70b9u90fdu4e0du96be", "type": 1, "create_time": "2018-07-31", "school": {"name": "u6df1u5733u6821u533a", "id": 3}, "id": 3}]
    View Code

    使用json格式化工具,效果如下:

    它将每一个数据类型做了自动转换。

    查看JsonResponse源代码

    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if safe and not isinstance(data, dict):
            raise TypeError(
                'In order to allow non-dict objects to be serialized set the '
                'safe parameter to False.'
            )
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)
        super(JsonResponse, self).__init__(content=data, **kwargs)
    View Code

    看这一行,是它来处理的。注意:cls表示这个类本身

    data = json.dumps(data, cls=encoder, **json_dumps_params)

    从上面的代码中,可以看出。针对查询对应的学校信息,使用了for循环。它是一个外键字段,

    那如果再查询一个外键字段呢?再来一个for循环?代码太冗长了!

    第三个版本:serializers

    下面会详细介绍

    五、serializers

     serializer 允许复杂数据(比如 querysets 和 model 实例)转换成python数据类型,然后可以更容易的转换成 json 或 xml 等。同时,serializer也提供了反序列化功能,允许解析数据转换成复杂数据类型。

    中文文档链接:

    https://q1mi.github.io/Django-REST-framework-documentation/api-guide/serializers_zh/

    声明序列化器

    class DBG(serializers.Serializer):  # 声明序列化器
        id = serializers.IntegerField()
        title = serializers.CharField()
        create_time = serializers.DateField()
        type = serializers.IntegerField()
        school = serializers.CharField(source="school.name")
    View Code

    注意:source="school.name" 表示school表中的name字段

    可以使用它来序列化和反序列化与DBG对象相应的数据。

    声明一个序列化器看起来非常像声明一个form。我们之前学习form组件时,将需要的字段的类型都指定好了!

    声明ModelSerializer

    通常你会想要与Django模型相对应的序列化类。

    ModelSerializer类能够让你自动创建一个具有模型中相应字段的Serializer类。

    这个ModelSerializer类和常规的Serializer类一样,不同的是

    • 它根据模型自动生成一组字段。
    • 它自动生成序列化器的验证器,比如unique_together验证器。
    • 它默认简单实现了.create()方法和.update()方法。

    声明一个ModelSerializer如下:

    class CYM(serializers.ModelSerializer):
        type = serializers.CharField(source='get_type_display')
    
        class Meta:
            model = models.Article
            fields = "__all__"  # ("id", "title", "type")
            depth = 1  # 官方推荐不超过10层
    View Code

    默认情况下,所有的模型的字段都将映射到序列化器上相应的字段。

    模型中任何关联字段比如外键都将映射到PrimaryKeyRelatedField字段。默认情况下不包括反向关联,除非像serializer relations文档中规定的那样显示包含。

    Model.get_FOO_display

    查看官方文档

    https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_FOO_display

    对于具有选择集的每个字段,该对象将具有一个get_FOO_display()方法,其中FOO是该字段的名称。 此方法返回字段的“可读”值。

    参数解释:

    source='get_type_display' 表获取type字段中选择集的值。

    不懂?看一下models.py中的Article表,看这一段

    # 文章的类型
        type = models.SmallIntegerField(
            choices=((1, "原创"), (2, "转载")),
            default=1
        )

    ORM是查询表的数据,那么这个type在真正存储时,是1或2。

    但是我想要得到"原创"和"转载",怎么办?那就需要我上面提到的get_type_display。

    注意:type的变量名和字段名必须保持一致,那么使用serializers后,结果集中type的值为"原创"和"转载",而不是1和2

    model = models.Article  表示Article表

    fields = "__all__"   表示所有字段,如果需要指定字段。可以写成这样fields = ("id", "title", "type")

    depth = 1   表示深度为1层。有外键关联时,才需要设置depth参数

    因为Article表和School表,是一对多的关系,它们之间的关系只有一层。假设说:School表和另外一个表(简称B表)有关系。Article表通过School表,要去查询B表的数据,那么层数就是2,以此类推!

    使用ModelSerializer

    def article_list(request):  # 查询所有
        # 去数据库查询所有的文章数据
        query_set = models.Article.objects.all()
        xbg = CYM(query_set, many=True)
        print(xbg.data)
        # 返回
        return JsonResponse(xbg.data, safe=False)
    View Code

    参数解释:

    many=True  表示能序列化多个对象

    什么意思?article表有多条数据,每一条数据,就是一个对象。我们需要查询表的所有记录,所以必须指定many=True。返回一条数据时,不需要指定many=True

    获取多条数据

    views.py完整代码如下:

    from django.shortcuts import render,HttpResponse
    from django.http import JsonResponse
    from app01 import models
    import json
    from rest_framework import serializers
    
    # Create your views here.
    
    class DBG(serializers.Serializer):  # 声明序列化器
        id = serializers.IntegerField()
        title = serializers.CharField()
        create_time = serializers.DateField()
        type = serializers.IntegerField()
        school = serializers.CharField(source="school.name")
    
    
    class CYM(serializers.ModelSerializer):  # 声明ModelSerializer
        #
        type = serializers.CharField(source='get_type_display')
    
        class Meta:
            model = models.Article
            fields = "__all__"  # ("id", "title", "type")
            depth = 1  # 官方推荐不超过10层
    
    
    def article_list(request):  # 查询所有
        # 去数据库查询所有的文章数据
        query_set = models.Article.objects.all()
        xbg = CYM(query_set, many=True)
        print(xbg.data)
        # 返回
        return JsonResponse(xbg.data, safe=False)
    View Code

    刷新页面,将数据复制一下,使用json格式化工具,效果如下:

    可以看到type的值不是数字,而是选择集中的值,它做了替换。是下面这一行,做了替换

    type = serializers.CharField(source='get_type_display')

    school的值,也能显示相关联的数据。

    CYM是通用的,可以多条,也可以一条。

    注意:多条的时候,需要加参数many=True。而一条,则不用!

    获取一条数据

    修改urls.py,增加一个路径

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^article_list/', views.article_list),
        url(r'article_detail/(d+)', views.article_detail),
    ]
    View Code

    修改views.py,增加视图函数

    from django.shortcuts import render,HttpResponse
    from django.http import JsonResponse
    from app01 import models
    import json
    from rest_framework import serializers
    
    # Create your views here.
    
    class DBG(serializers.Serializer):  # 声明序列化器
        id = serializers.IntegerField()
        title = serializers.CharField()
        create_time = serializers.DateField()
        type = serializers.IntegerField()
        school = serializers.CharField(source="school.name")
    
    
    class CYM(serializers.ModelSerializer):  # 声明ModelSerializer
        #
        type = serializers.CharField(source='get_type_display')
    
        class Meta:
            model = models.Article
            fields = "__all__"  # ("id", "title", "type")
            depth = 1  # 官方推荐不超过10层
    
    
    def article_list(request):  # 查询所有
        # 去数据库查询所有的文章数据
        query_set = models.Article.objects.all()
        xbg = CYM(query_set, many=True)
        print(xbg.data)
        # 返回
        return JsonResponse(xbg.data, safe=False)
    
    
    def article_detail(request, id):  # 查询单条数据
        article_obj = models.Article.objects.filter(id=id).first()
        xcym = CYM(article_obj)
        return JsonResponse(xcym.data)
    View Code

    注意:使用这一行代码

    from rest_framework import serializers

    必须要用pip install djangorestframework  安装!!!

    刷新页面,访问url:  http://127.0.0.1:8000/article_detail/1

    使用格式化工具,效果如下:

    总结:

    使用ORM对象转换为json对象时,推荐使用serializers

    六、Postman使用

    Postman一款非常流行的API调试工具。不仅可以调试简单的css、html、脚本等简单的网页基本信息,它还能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..),附带任何数量的参数+ headers。对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。

    官网地址:

    www.getpostman.com

    使用windows安装之后,打开主程序,跳过登录

     访问文章列表 http://127.0.0.1:8000/article_list/

    访问文章详情   http://127.0.0.1:8000/article_detail/1

     总结:

    1. 使用Django 的视图 自己序列化
        1. HttpResponse
        2. JsonResponse
        3. serializers
    
    2. 使用Django REST Framework 框架的序列化工具类
        1. 安装
            pip install djangorestframework
        2. 导入
            from rest_framework import serializers
        3. 使用
            class ArticleSerializer(serializers.Serializer):
                ...
    View Code

    七、外部python脚本调用django

    有些情况下,我们需要使用python脚本来调用django,从而方便使用django提供的一些指令!

    调试ORM

    在django项目根目录下创建文件test_orm.py,它和manage.py是同级的

    import os
    
    if __name__ == "__main__":
        # 设置django环境
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_drf.settings")
        import django
        django.setup()
    
        from app01 import models
    
        obj = models.Article.objects.filter(id=1).values()
        print(obj)
    View Code

    执行脚本,输出如下:

    <QuerySet [{'title': 'Python三年用不上', 'id': 1, 'school_id': 1, 'type': 1, 'update_time': datetime.date(2018, 7, 31), 'create_time': datetime.date(2018, 7, 31)}]>

    清理过期session

    如果用户主动退出,session会自动清除,如果没有退出就一直保留,记录数越来越大,要定时清理没用的session。

    django中已经提供了这个方法,推荐把它加入到crontab中自动清理过期的session,防止session表记录过大,影响访问速度。

    python E:python_scriptdjango框架day15about_drfmanage.py clearsessions
  • 相关阅读:
    python 利用爬虫获取页面上下拉框里的所有国家
    python3 requests 进行接口测试、爬虫使用总结
    Tomcat设置最佳线程数总结
    Java中实现对象的比较:Comparable接口和Comparator接口
    堆排序算法
    快速排序算法2---以第一个元素作为主元
    字符串匹配---暴力匹配算法
    快速排序算法
    Spring中@Autowired注解与自动装配
    Spring的注解
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9396452.html
Copyright © 2011-2022 走看看