V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
rapospectre
V2EX  ›  Python

用 Django 零成本快速实现 API 服务

  •  
  •   rapospectre ·
    bluedazzle · 2016-06-15 11:30:53 +08:00 · 8494 次点击
    这是一个创建于 3117 天前的主题,其中的信息可能已经有所发展或是发生改变。

    写后台的时候经常需要写数据接口,这时就需要用到序列化工具, 而默认到序列化工具对 Django model 的序列化支持有限。 同时 Django 本身的序列化工具我在使用时也觉得有诸多不便,因此我尝试自己写了一个快速序列化工具,帮助我快速简单的实现数据接口。

    Django Simple Serializer 是一个可以帮助开发者快速将 Django 数据或者 python data 序列化为 json|raw 数据的工具。

    ##为什么要用 Django Simple Serializer ?

    对于序列化 Django 数据的解决方案已经有以下几种:

    ###django.core.serializers Django 内建序列化器, 它可以序列化 Django model query set 但无法直接序列化单独的 Django model 数据。如果你的 model 里含有混合数据 , 这个序列化器同样无法使用(如果你想直接使用序列化数据). 除此之外, 如果你想直接把序列化数据返回给用户,显然它包含了很多敏感及对用户无用对信息。 ###QuerySet.values() 和上面一样, 如果你的 model 里有 DateTimeField 或者其他特殊的 Field 以及额外数据, QuerySet.values() 同样没法工作。 ###django-rest-framework serializers django-rest-framework 是一个可以帮助你快速构建 REST API 的强力框架。 他拥有完善的序列化器,但在使用之前你需要花费一些时间入门, 并学习 cbv 的开发方式, 对于有时间需求的项目或者已经存在的项目需要增加数据接口时显然这不是最好的解决方案。 ###django simple serializer 我希望可以快速简单的序列化数据, 所以我设计了一种可以不用任何额外的配置与学习而将 Django data 或者 python data 序列化为相应的数据的简单的方式。 这就是为什么我写了 django simple serializer 。


    ##运行需求 Django >= 1.5

    Python 2.5 及以上 (暂不支持 python 3)

    ##安装

    Install using pip:

    pip install django-simple-serializer
    

    ##使用 django simple serializer 进行开发 ###序列化 Django data 假设我们有以下 Django models :

    class Classification(models.Model):
        c_name = models.CharField(max_length=30, unique=True)
    
    class Article(models.Model):
        caption = models.CharField(max_length=50)
        classification = models.ForeignKey(Classification, related_name='cls_art')
        content = models.TextField()
        publish = models.BooleanField(default=False)
    

    使用 django simple serializer 的简单例子:

    from dss.Serializer import serializer
    article_list = Article.objects.all()
    data = serializer(article_list)
    

    data:

    [{'read_count': 0, 'create_time': 1432392456.0, 'modify_time': 1432392456.0, 'sub_caption': u'first', 'comment_count': 0, u'id': 31}, {'read_count': 0, 'create_time': 1432392499.0, 'modify_time': 1432392499.0, 'sub_caption': u'second', 'comment_count': 0, u'id': 32}]
    

    默认情况下, 序列器会返回一个 list 或者 dict(对于单个 model 实例), 你可以设置参数 “ output_type ” 来决定序列器返回 json/raw.


    ##API 手册

    ####dss.Serializer 提供序列器

    function serializer(data, datetime_format='timestamp', output_type='raw', include_attr=None, except_attr=None, foreign=False, many=False)

    ####Parameters:

    • data(Required|(QuerySet, Page, list, django model object))-待处理数据
    • datetime_format(Optional|string)-如果包含 datetime 将 datetime 转换成相应格式.默认为 "timestamp"(时间戳)
    • output_type(Optional|string)-serialize type. 默认“ raw ”原始数据,即返回 list 或 dict
    • include_attr(Optional|(list, tuple))-只序列化 include_attr 列表里的字段。默认为 None
    • exclude_attr(Optional|(list, tuple))-不序列化 except_attr 列表里的字段。默认为 None
    • foreign(Optional|bool)-是否序列化 ForeignKeyField 。 include_attr 与 exclude_attr 对 ForeignKeyField 依旧有效。 默认为 False
    • many(Optional|bool)-是否序列化 ManyToManyField 。 include_attr 与 exclude_attr 对 ManyToManyField 依旧有效 默认为 False

    ####用法:

    datetime_format:

    |parameters|intro| | -------------- | :---: | |string|转换 datetime 为字符串。如: "2015-05-10 10:19:22"| |timestamp|转换 datetime 为时间戳。如: "1432124420.0"|

    例子:

    from dss.Serializer import serializer
    article_list = Article.objects.all()
    data = serializer(article_list, datetime_format='string', output_type='json')
    

    data:

    [
        {
            "read_count": 0,
            "sub_caption": "first",
            "publish": true,
            "content": "first article",
            "caption": "first",
            "comment_count": 0,
            "create_time": "2015-05-23 22:47:36",
            "modify_time": "2015-05-23 22:47:36",
            "id": 31
        },
        {
            "read_count": 0,
            "sub_caption": "second",
            "publish": false,
            "content": "second article",
            "caption": "second",
            "comment_count": 0,
            "create_time": "2015-05-23 22:48:19",
            "modify_time": "2015-05-23 22:48:19",
            "id": 32
        }
    ]
    

    output_type

    |parameters|intro| | -------------- | :---: | |raw|将 list 或 dict 中的特殊对象序列化后输出为 list 或 dict| |dict|同 raw|
    |json|转换数据为 json|

    ~~xml 转换数据为 xml~~ (暂时去除)

    例子:

    from dss.Serializer import serializer
    article_list = Article.objects.all()[0]
    data = serializer(article_list, output_type='json')
    

    data:

    {
            "read_count": 0,
            "sub_caption": "first",
            "publish": true,
            "content": "first article",
            "caption": "first",
            "comment_count": 0,
            "create_time": "2015-05-23 22:47:36",
            "modify_time": "2015-05-23 22:47:36",
            "id": 31
        }
    

    include_attr

    例子:

    from dss.Serializer import serializer
    article_list = Article.objects.all()
    data = serializer(article_list, output_type='json', include_attr=('content', 'caption',))
    

    data:

    [
        {
            "content": "first article",
            "caption": "first"
        },
        {
            "content": "second article",
            "caption": "second"
        }
    ]
    

    exclude_attr

    例子:

    from dss.Serializer import serializer
    article_list = Article.objects.all()
    data = serializer(article_list, output_type='json', except_attr=('content',))
    

    data:

        [
            {
                "read_count": 0,
                "sub_caption": "first",
                "publish": true,
                "caption": "first",
                "comment_count": 0,
                "create_time": 1432392456,
                "modify_time": 1432392456,
                "id": 31
            },
            {
                "read_count": 0,
                "sub_caption": "second",
                "publish": false,
                "caption": "second",
                "comment_count": 0,
                "create_time": 1432392499,
                "modify_time": 1432392499,
                "id": 32
            }
        ]
    

    foreign

    序列化数据中的 ForeignKeyField 及其子项目

    例子:

    from dss.Serializer import serializer
    article_list = Article.objects.all()
    data = serializer(article_list, output_type='json', include_attr=('classification', 'caption', 'create_time', foreign=True)
    

    data:

        [
            {
                "caption": "first",
                "create_time": 1432392456,
                "classification": {
                    "create_time": 1429708506,
                    "c_name": "python",
                    "id": 1,
                    "modify_time": 1429708506
                }
            },
            {
                "caption": "second",
                "create_time": 1432392499,
                "classification": {
                    "create_time": 1430045890,
                    "c_name": "test",
                    "id": 5,
                    "modify_time": 1430045890
                }
            }
        ]
    

    many 序列化 ManyToManyField

    example:

    from dss.Serializer import serializer
    article_list = Article.objects.all()
    data = serializer(article_list, output_type='json', include_attr=('classification', 'caption', 'create_time', many=True)
    

    测试数据无 ManyToManyField ,数据格式同上

    ####dss.Mixin 提供序列器 Mixin

    class JsonResponseMixin(object)
        datetime_type = 'string'                # 输出 datetime 时间格式。默认为“ string ”,可选参数相见 dss.Serializer.serializer
        foreign = False                         # 是否序列化 ForeignField 。默认为 False
        many = False                            # 是否序列化 ManyToManyField 。默认为 False
        include_attr = None                     # 只序列化 include_attr 包含的属性。默认为 None,接受一个包含属性名称的 tuple
        exclude_attr = None                     # 不序列化 exclude_attr 包含的属性。默认为 None,接受一个包含属性名称的 tuple
    

    ####说明:

    将普通 class based view 转换为返回 json 数据的 class based view ,适用于 DetailView 等

    ####用法:

    例子:

    # view.py
    from dss.Mixin import JsonResponseMixin
    from django.views.generic import DetailView
    from model import Article
    
    class TestView(JsonResponseMixin, DetailView):
        model = Article
        datetime_type = 'string'
        pk_url_kwarg = 'id'
    
    
    # urls.py
    from view import TestView
    urlpatterns = patterns('',
        url(r'^test/(?P<id>(\d)+)/$', TestView.as_view()),
    )
    

    访问:localhost:8000/test/1/

    response:

    {
        "article": {
            "classification_id": 5, 
            "read_count": 0, 
            "sub_caption": "second", 
            "comments": [], 
            "content": "asdfasdfasdf", 
            "caption": "second", 
            "comment_count": 0, 
            "id": 32, 
            "publish": false
        }, 
        "object": {
            "classification_id": 5, 
            "read_count": 0, 
            "sub_caption": "second", 
            "comments": [], 
            "content": "asdfasdfasdf", 
            "caption": "second", 
            "comment_count": 0, 
            "id": 32, 
            "publish": false
        }, 
        "view": ""
    }
    

    class MultipleJsonResponseMixin(JsonResponseMixin):

    ####说明:

    将列表类视图转换为返回 json 数据的类视图,适用于 ListView 等

    ####用法:

    例子:

    # view.py
    from dss.Mixin import MultipleJsonResponseMixin
    from django.views.generic import ListView
    from model import Article
    
    class TestView(MultipleJsonResponseMixin, ListView):
        model = Article
        query_set = Article.objects.all()
        paginate_by = 1
        datetime_type = 'string'
    
    
    # urls.py
    from view import TestView
    urlpatterns = patterns('',
        url(r'^test/$', TestView.as_view()),
    )
    

    访问:localhost:8000/test/

    response:

    {
        "paginator": "", 
        "article_list": [
            {
                "classification_id": 1, 
                "read_count": 2, 
                "sub_caption": "first", 
                "content": "first article", 
                "caption": "first", 
                "comment_count": 0, 
                "publish": false, 
                "id": 31
            }, 
            {
                "classification_id": 5, 
                "read_count": 0, 
                "sub_caption": "", 
                "content": "testseteset", 
                "caption": "hehe", 
                "comment_count": 0, 
                "publish": false, 
                "id": 33
            }, 
            {
                "classification_id": 5, 
                "read_count": 0, 
                "sub_caption": "second", 
                "content": "asdfasdfasdf", 
                "caption": "second", 
                "comment_count": 0, 
                "publish": false, 
                "id": 32
            }
        ], 
        "object_list": [
            {
                "classification_id": 1, 
                "read_count": 2, 
                "sub_caption": "first", 
                "content": "first article", 
                "caption": "first", 
                "comment_count": 0, 
                "publish": false, 
                "id": 31
            }, 
            {
                "classification_id": 5, 
                "read_count": 0, 
                "sub_caption": "", 
                "content": "testseteset", 
                "caption": "hehe", 
                "comment_count": 0, 
                "publish": false, 
                "id": 33
            }, 
            {
                "classification_id": 5, 
                "read_count": 0, 
                "sub_caption": "second", 
                "content": "asdfasdfasdf", 
                "caption": "second", 
                "comment_count": 0, 
                "publish": false, 
                "id": 32
            }
        ], 
        "page_obj": {
            "current": 1, 
            "next": 2, 
            "total": 3, 
            "page_range": [
                {
                    "page": 1
                }, 
                {
                    "page": 2
                }, 
                {
                    "page": 3
                }
            ], 
            "previous": null
        }, 
        "is_paginated": true, 
        "view": ""
    }
    

    class FormJsonResponseMixin(JsonResponseMixin):

    ####说明:

    将普通 class based view 转换为返回 json 数据的 class based view ,适用于 CreateView 、 UpdateView 、 FormView 等

    ####用法:

    例子:

    # view.py
    from dss.Mixin import FormJsonResponseMixin
    from django.views.generic import UpdateView
    from model import Article
    
    class TestView(FormJsonResponseMixin, UpdateView):
        model = Article
        datetime_type = 'string'
        pk_url_kwarg = 'id'
    
    
    # urls.py
    from view import TestView
    urlpatterns = patterns('',
        url(r'^test/(?P<id>(\d)+)/$', TestView.as_view()),
    )
    

    访问:localhost:8000/test/1/

    response:

    {
        "article": {
            "classification_id": 5, 
            "read_count": 0, 
            "sub_caption": "second", 
            "content": "asdfasdfasdf", 
            "caption": "second", 
            "comment_count": 0, 
            "id": 32, 
            "publish": false
        }, 
        "form": [
            {
                "field": "caption"
            }, 
            {
                "field": "sub_caption"
            }, 
            {
                "field": "read_count"
            }, 
            {
                "field": "comment_count"
            }, 
            {
                "field": "classification"
            }, 
            {
                "field": "content"
            }, 
            {
                "field": "publish"
            }
        ], 
        "object": {
            "classification_id": 5, 
            "read_count": 0, 
            "sub_caption": "second", 
            "content": "asdfasdfasdf", 
            "caption": "second", 
            "comment_count": 0, 
            "id": 32, 
            "publish": false
        }, 
        "view": ""
    }
    

    ####对额外数据的序列化支持:

    当我们想在 model 中加入一些额外的数据并也想被序列化时, 现在可以这样做:

        def add_extra(article):
            comments = Comment.objects.filter(article=article)
            setattr(article, 'comments', comments)
        
        articles = Article.objects.all()
        map(add_extra, articles)
        result = serializer(articles)
    

    序列化的结果数据中将会包含"comments"哦.

    额外加入的数据可以是一个普通的数据类型、 另一个 Django model 、 字典、 列表甚至 QuerySet

    django simple serializer 的实际例子: 个人网站后台数据接口

    项目地址: django-simple-serializer

    欢迎大家拍砖并提供宝贵意见。

    第 1 条附言  ·  2016-06-15 12:46:13 +08:00

    文中这里格式乱了,重发一下:

    为什么要用 Django Simple Serializer ?

    对于序列化 Django 数据的解决方案已经有以下几种:

    django.core.serializers Django

    内建序列化器, 它可以序列化 Django model query set 但无法直接序列化单独的 Django model 数据。如果你的 model 里含有混合数据 , 这个序列化器同样无法使用(如果你想直接使用序列化数据). 除此之外, 如果你想直接把序列化数据返回给用户,显然它包含了很多敏感及对用户无用对信息。 ###QuerySet.values() 和上面一样, 如果你的 model 里有 DateTimeField 或者其他特殊的 Field 以及额外数据, QuerySet.values() 同样没法工作。

    django-rest-framework serializers

    django-rest-framework 是一个可以帮助你快速构建 REST API 的强力框架。 他拥有完善的序列化器,但在使用之前你需要花费一些时间入门, 并学习 cbv 的开发方式, 对于有时间需求的项目或者已经存在的项目需要增加数据接口时显然这不是最好的解决方案。

    django simple serializer

    我希望可以快速简单的序列化数据, 所以我设计了一种可以不用任何额外的配置与学习而将 Django data 或者 python data 序列化为相应的数据的简单的方式。 这就是为什么我写了 django simple serializer 。

    11 条回复    2017-05-22 18:54:03 +08:00
    felixzhu
        1
    felixzhu  
       2016-06-15 11:58:45 +08:00
    这个和 django-rest-framework 提供的 serializer 之类的有什么区别啊
    rapospectre
        2
    rapospectre  
    OP
       2016-06-15 12:06:46 +08:00
    @felixzhu 序列化的结果是一样的,但是我写的这个使用非常简单, 直接用就可以。 django-rest-framework 和它相比的弊端我在文中提到了。当然已经使用 drf 并且非常顺手也可以看看我这个呀,吐吐槽,看看哪里做的不好 0.0
    brucedone
        3
    brucedone  
       2016-06-15 12:54:08 +08:00
    why not flask ?
    rapospectre
        4
    rapospectre  
    OP
       2016-06-15 13:51:23 +08:00
    @brucedone 这就是给 Django 的一个解决方案,当然用 flask 做 API 服务也可以,@-@
    daimoon
        5
    daimoon  
       2016-06-16 08:13:33 +08:00
    不过我还是觉的有必要花时间学习下 restframework 。学习成本略高,确实非常方便。
    rapospectre
        6
    rapospectre  
    OP
       2016-06-16 09:42:24 +08:00
    @daimoon 是的,不过你可以拿出学 drf 百分之一的时间试试这个呀,也很方便哒。
    nimdanoob
        7
    nimdanoob  
       2016-06-16 15:41:48 +08:00
    good work
    rapospectre
        8
    rapospectre  
    OP
       2016-06-23 09:52:25 +08:00
    @nimdanoob 谢谢!
    KgM4gLtF0shViDH3
        9
    KgM4gLtF0shViDH3  
       2017-05-21 18:50:03 +08:00
    看 GitHub 上已经支持 python3 了,作者好勤快呀,支持一个。
    rapospectre
        10
    rapospectre  
    OP
       2017-05-22 16:15:45 +08:00
    @bestkayle 谢谢支持!
    KgM4gLtF0shViDH3
        11
    KgM4gLtF0shViDH3  
       2017-05-22 18:54:03 +08:00
    @rapospectre #10 还需要头条大神的指教呢-0-
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3610 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 10:23 · PVG 18:23 · LAX 02:23 · JFK 05:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.