在django restframework中实现google的部分响应

djangorestframework-jsonmask的Python项目详细描述


Build StatusCoverage StatusPyPI Version


概述

在django restframework中实现google的部分响应

要求

  • Python(2.7、3.6、3.7)
  • Django(1.11、2.0、2.1)

安装

使用pip安装…

$ pip install djangorestframework-jsonmask

示例

大多数支持?fields=样式数据剪枝的drf插件都是在serializaton层进行剪枝的。许多水合物完整的orm对象,包括它们的所有详细关系,然后在json序列化之前立即剪切不需要的数据。任何不需要的相关数据仍然会从数据库中获取并水合到django orm对象中,这严重破坏了字段修剪的有用性。

rest_framework_jsonmask旨在通过允许开发人员声明性地增加与单个请求直接相关的queryset来做得更好。在此模式下,您只需在viewset.queryset上声明基本的queryset和任何通用关系,而将所有其他增强保留为运行时opt-ins。

使用^ {CD3>},首先在适当的代码中包含它的视图集和序列化混合器。以下示例取自此库自己的单元测试中使用的小型项目。

# api/views.pyfromrest_framework_jsonmask.viewsimportOptimizedQuerySetMixinclassTicketViewSet(OptimizedQuerySetMixin,viewsets.ReadOnlyModelViewSet):# Normally, for optimal performance, you would apply the `select_related('author')`# call to the base queryset, but that is no longer desireable for data relationships# that your frontend may stop asking for.queryset=Ticket.objects.all()serializer_class=TicketSerializer# Data-predicate declaration is optional, but encouraged. This# is where the library really shines!@data_predicate('author')defload_author(self,queryset):returnqueryset.select_related('author')# api/serializers.pyfromrest_framework_jsonmask.serializersimportFieldsListSerializerMixinclassTicketSerializer(FieldsListSerializerMixin,serializers.ModelSerializer):# Aside from the mixin, everything else is exactly like normalauthor=UserSerializer()classMeta:models=my_module.models.Ticketfields=('id','title','body','author',)

现在,您已经将api设置为跳过不必要的连接(可能还有预取),除非请求客户端需要该数据。让我们考虑几个假设的请求和它们各自将收到的响应。(为简洁起见,在这些示例中,我将假设分页已关闭。)

GET /api/tickets/200 OK[    {        "id": 1,        "title": "This is a ticket",        "body": "This is its text",        "author": {            "id": 5,            "username": "HomerSimpson",        }    }]

因为没有提供?fieldsquerystring参数,所以仍像正常一样加载和序列化作者记录。

Note: rest_framework_jsonmask treats all requests that lack any field definition as if all possible data is requested, and thus executes all data predicates. In the above example, author data was loaded via selected_related('author'), and not N+1 queries.


GET /api/tickets/?fields=id,title,body200 OK[    {        "id": 1,        "title": "This is a ticket",        "body": "This is its text"    }]

在这个例子中,由于没有指定author,它不仅没有在响应负载中返回,而且从一开始就没有被查询或序列化过。


GET /api/tickets/?fields=id,title,body,author/username200 OK[    {        "id": 1,        "title": "This is a ticket",        "body": "This is its text",        "author": {            "username": "HomerSimpson",        }    }]

在本例中,author数据是通过?fields声明加载的,但是响应中不会出现不需要的键。

嵌套关系

这一切都很好也很有趣,但是如果author很少使用但也很昂贵的关系呢?rest_framework_jsonmask通过上述完全相同的机制支持这一点,尽管有时对细节的额外关注可能很重要。现在假设AuthorSerializer看起来是这样:

classAuthorSerializer(FieldsListSerializerMixin,serializers.ModelSerializer):accounts=AccountSerializer(many=True)classMeta:model=settings.AUTH_USER_MODELfields=('id','username','email','photo','accounts',...)

当然,如果accounts是敏感的内部数据,那么您可能不使用this序列化程序进行外部api使用。当然,这将解决如何决定是否序列化accounts数据的问题——提供的序列化程序对该字段一无所知!但是,假设在我们的例子中,accounts对于公共消费是安全的,并且一些票务api调用需要它来进行测试,而其他的则不需要。在这种情况下,我们将重新定义视图集,如下所示:

classTicketViewSet(OptimizedQuerySetMixin,viewsets.ReadOnlyModelViewSet):queryset=Ticket.objects.all()serializer_class=TicketSerializer@data_predicate('author')defload_author(self,queryset):returnqueryset.select_related('author')# Add this extra data_predicate with prefetches `accounts` if and only if# the requests promises to use that information@data_predicate('author.accounts')defload_author_with_accounts(self,queryset):returnqueryset.select_related('author').prefetch_related('author__accounts')

现在,由客户决定以下哪一个选项(或任何其他可以想象的选项)最合适:

 # Includes specified local fields plus all author fields and relationshipsGET /api/tickets/?fields=id,title,author200 OK[    {        "id": 1,        "title": "This is a ticket",        "author": {            "id": 5,            "username": "HomerSimpson",            "accounts": [                {"all_fields": "will_be_present"}            ]        }    }]

# Includes specified local fields plus specified author fields and relationshipsGET /api/tickets/?fields=id,title,author(username,photo)200 OK[   {       "id": 1,       "title": "This is a ticket",       "author": {           "username": "HomerSimpson",           "photo": "image_url"       }   }]

# Includes specified local fields plus specified author fields and relationships plus specified accounts fields and relationshipsGET /api/tickets/?fields=id,title,author(id,accounts(id,type_of,date))200 OK[   {       "id": 1,       "title": "This is a ticket",       "author": {           "id": 5,           "accounts": [               {                   "id": 8001,                   "type_of": "business",                   "date": 2018-01-01T12:00:00Z"               },               {                   "id": 6500,                   "type_of": "trial",                   "date": 2017-06-01T12:00:00Z"               }           ]       }   }]

简言之,只要序列化程序的整个链实现FieldsListSerializerMixin,就可以实现?fields声明的任意深度嵌套。然而,在实践中,由于关系是昂贵的水合物,您可能希望限制该信息,并使用视图集方法上的@data_predicate装饰器控制实际加载的数据。

测试

$ make tests

或者让他们在换车时继续跑:

$ make watch

您还可以使用优秀的tox测试工具对所有受支持的python和django版本运行测试。全局安装tox,然后只需运行:

$ tox

文档

$ make docs

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java这个简单的复制程序是如何工作的   集合Java 8:在列表中映射列表   java为什么hibernate不读取事务中的更新?   在Java中使用泛型返回空值   java如何在ImageView不工作时进行触觉反馈   java CardLayout不会切换回第一个面板   保存集合时发生java Hibernate映射异常   java支持通过Jena对SPARQL请求进行推理?   Java数组在循环内不工作   安卓 XML/Java按钮单击以更改文本视图   java JVM在写入XLSX文件(POI)时崩溃   java如何在运行时创建RollingFileAppender(web应用程序侦听器)并替换配置xml中定义的ConsoleAppender   hibernate和json的java问题   java查找浏览器SWT浏览器的类型/版本