GVKun编程网logo

Django Rest Framework和JSONField

14

这篇文章主要围绕DjangoRestFramework和JSONField展开,旨在为您提供一份详细的参考资料。我们将全面介绍DjangoRestFramework和JSONField,同时也会为您带

这篇文章主要围绕Django Rest Framework和JSONField展开,旨在为您提供一份详细的参考资料。我们将全面介绍Django Rest Framework和JSONField,同时也会为您带来1 Django REST Framework 开发 ---- 原生 Django View 热身、13 在 Django REST framework 善用 SerializerMethodField方法、2 Django REST Framework 开发 ---- APIView、4 Django REST Framework 开发 ---- ViewSet的实用方法。

本文目录一览:

Django Rest Framework和JSONField

Django Rest Framework和JSONField

给定具有JSONField的Django模型,使用Django Rest Framework对其进行序列化和反序列化的正确方法是什么?

我已经尝试过创建一个自定义serializers.WritableField和重写to_native以及from_native

from json_field.fields import JSONEncoder, JSONDecoderfrom rest_framework import serializersclass JSONFieldSerializer(serializers.WritableField):    def to_native(self, obj):    return json.dumps(obj, cls = JSONEncoder)    def from_native(self, data):        return json.loads(data, cls = JSONDecoder)

但是,当我尝试使用来更新模型时partial=True,JSONField对象中的所有浮点数都变为字符串。

答案1

小编典典

如果您使用的是Django Rest Framework> = 3.3,那么现在将包含JSONField序列化程序。现在这是正确的方法。

如果您使用的是Django Rest Framework <3.0,请参阅gzerone的答案。

如果您使用的是DRF 3.0-3.2,并且无法升级,也不需要序列化二进制数据,请按照以下说明进行操作。

首先声明一个字段类:

from rest_framework import serializersclass JSONSerializerField(serializers.Field):    """ Serializer for JSONField -- required to make field writable"""    def to_internal_value(self, data):        return data    def to_representation(self, value):        return value

然后像这样将字段添加到模型中

class MySerializer(serializers.ModelSerializer):    json_data = JSONSerializerField()

而且,如果确实需要序列化二进制数据,则始终可以复制正式发行代码

1 Django REST Framework 开发 ---- 原生 Django View 热身

1 Django REST Framework 开发 ---- 原生 Django View 热身

在正式开始 Django REST Framework 学习之前,先用 django.core.serializers 和原生的 Django View 类来实现一次数据的序列化数据。

 

下面的例子展示了,是如何解决序列化 JSON 数据的,前提:给Products的Model已经创建完

创建 Django 项目,并修改 urls.py 文件:

1 from django.views.generic import TemplateView
2 from product.views import ProductsListView
3 
4 
5 urlpatterns = [
6     url(r''^admin/'', admin.site.urls),
7     url(r''^products/'', ProductsListView.as_view(), name="product-list"),
8 ]

 

创建 view.py 文件并写入如下内容:

 1 import json
 2 
 3 from django.http import JsonResponse
 4 from django.core import serializers
 5 from django.views.generic.base import View
 6 
 7 from products.models import Product
 8 
 9 
10 class ProductListView(View):
11     def get(self, request):
12         products = Product.objects.all()
13         json_data = serializers.serialize(''json'', products)  # 将django model 得到的对象序列化成 json 类型
14         json_data = json.loads(json_data)
15 
16         return JsonResponse(json_data, safe=False)  # safe = False 因为json_data是 non-dict 类型,不然会报错

注:在打开网页显示数据时需下载chrome jsonview插件


这样一个基本的django 使用json数据类型调取数据的过程就完成了,但是会有以下问题:

  1. 图片,日期格式支持不够(仅会显示图片相对路径)
  2. 主键JSON字段之外,使得调用起来会不方便
  3. 文档需要手动写,缺乏规范性且效率低下
  4. 输入验证缺失 (类似于表单的认证)
  5. 等等

 

13 在 Django REST framework 善用 SerializerMethodField方法

13 在 Django REST framework 善用 SerializerMethodField方法

 01-使用SerializerMethodField 来优化不必要的查询

class RepairQueueSerializer(serializers.ModelSerializer):
    # rq_base = serializers.CharField()
    tasks_not_finish = serializers.SerializerMethodField()
    tasks_wait_for = serializers.SerializerMethodField()
    tasks_finish = serializers.SerializerMethodField()

    class Meta:
        model = models.RepairQueue

        fields = (''rqid'', ''rq_type'', ''rq_desc'', ''rq_level'', ''rq_time'', ''rq_user'', ''rq_contact'', ''rq_status'',
                  ''rq_report'', ''rq_tasks_choice'', ''rq_work_status'', ''tasks_not_finish'', ''tasks_wait_for'', ''tasks_finish'')

    def get_tasks_not_finish(self, obj):
        return models.RepairQueue.objects.filter(rq_tasks_choice=''未完成'').count()

    def get_tasks_wait_for(self, obj):
        return models.RepairQueue.objects.filter(rq_tasks_choice=''待验收'').count()

    def get_tasks_finish(self, obj):
        return models.RepairQueue.objects.filter(rq_tasks_choice=''已完成'').count()

    def create(self, validated_data):
        validated_data[''rqid''] = DBHelper.get_id(''uni_repairqueue'', ''WYWX'')
        return models.RepairQueue.objects.create(**validated_data)

 

添加一个 get_tasks_not_finish 方法,这个方法的命名规则就是在上面声明的属性前面加上个 “get_” 前缀,并接受一个 obj 参数,这个 obj 参数就是当前的 models.RepairQueue 对象实例。

1. serializer可以做逻辑上的操作,然而最好不要做查询(你可以用SerializerMethodField做一些数据转换例如0变为假1变为真什么的,然而最好不要做复杂的数据库查询),这种事情可以在view上做好(注意可以用select_related减少多次查询),
因为这是每一个model都要serializer一次。
2. 如果说跟前端对的修改和查询使用不同的serializer,那么你就写两个,不希望修改的字段加上readonly(或者放在readonly_fields里面)

 02-使用 SerializerMethodField 获取关联的model的字段

对于外键字段实现显示被关联的字段而不是id

例:外键

class CommentSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField(''get_user_name'')
 
    class Meta:
        model = Comment
        fields = (''name'', ''create_time'', ''text'')
 
    def get_user_name(self, obj):
        return obj.author.nickname

如上图,obj是对应的模型,此处是Comment。author是Comment的ForeignKeyField,nickName是Author的一个字段。

例:多对多

def get_who_like_it(self, obj):
    return [author.nickname for author in obj.like.all()]

 参考:https://blog.csdn.net/csdn_yi_e/article/details/86475587

2 Django REST Framework 开发 ---- APIView

2 Django REST Framework 开发 ---- APIView

APIView

通过看源码可以发现 APIView 直接继承了 Django View 这个基类,在此基础上添加了 render_classes, parser_classes, authentication_classes 等等,由此可见 APIView 还是比较偏底层的,但通过使用它可以相对灵活实现一些自定义功能。
介绍 APIView: https://www.django-rest-framework.org/api-guide/views/

APIView 类与 Django 原生 View 有以下区别:

  • 当客户端发来请求会被 DRF 的 Request 对象中的 handler 方法(get, post etc.) 处理,而非 Django 的 HttpRequest 对象
  • Handler 方法返回 DRF 的 Request 对象, View 会管理返回结果最终渲染回 Response
  • 任何 APIException 都会被捕获且返回相应的报错
  • 收到的客户端请求会先被进行权限认证等步骤后才分发给 handler 方法

在使用上 APIView 类与 View 几乎相差不大。收到的客户端请求会被分发到相关的 handler 方法如:.get (), .post ()。由于不同 API 的 policy 的不同,APIView 中设置了相应的属性。

下面编写一个简单的 view.py with APIView
参照: https://www.django-rest-framework.org/tutorial/3-class-based-views/

 1 from products.models import Product
 2 from products.serializers import ProductSerializer
 3 from django.http import Http404
 4 from rest_framework.views import APIView
 5 from rest_framework.response import Response
 6 from rest_framework import status
 7 
 8 
 9 class ProductListView(APIView):    
10    """
11    List all products
12    """
13     def get(self, request, format=None):
14         products = Product.objects.all()
15         products_serializer = ProductSerializer(products, many=True)  # 序列化 products 对象成 json 格式;many 表示返回多条数据
16         return Response(products_serializer.data)
17 
18     def post(self, request, format=None):
19         serializer = ProductSerializer(data=request.data)
20         if serializer.is_valid():
21             serializer.save()  # call serializer "create" method
22             return Response(serializer.data, status=status.HTTP_201_CREATED)
23         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

注: ProductSerializer 实现见之前的文章 (https://www.cnblogs.com/crazy-chinese/p/9828095.html)

 

4 Django REST Framework 开发 ---- ViewSet

4 Django REST Framework 开发 ---- ViewSet

After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output.

Routing 的职责是,决定哪一个 controller 应该对于收到的 request 做出回应,所以 controller 的作用是处理 request 并产生相对的 output 回应。
Aus <https://www.django-rest-framework.org/api-guide/viewsets/>


DRF 允许多个相关的 View 共同完善某个类的功能(多继承,类似 Java 的接口),并将诸多功能封装在单个类中,这样的类叫做 ViewSet。
一个 ViewSet 的类其实是某种 class-based View,该 View 不提供任何方法的 Handler 如:.get(), .post(), 但是提供 actions 如:.list(), .create()。 这些 actions 有助于使你的程序变得更加动态 (比如动态设置 Serilizer 会变得很方便)。
ViewSet 方法的 handler 则使用 .as_view()方法绑定到 View 的最终的相应操作上。一般 viewset 不在 urlconf 中配置,而是将其通过 router 类注册到应用程序上,router 会负责根据用户请求分发给相应 url。

相关知识点:ViewSetMixin
ViewSetMixin 重写 as_view 的信息,来达到定制路由的效果, 这个能让我们注册 url 变得更加简单。ViewSetMixin的源码部分如下:

1 class ViewSetMixin(object):
2     @classonlymethod
3     def as_view(cls, actions=None, **initkwargs):
4       ······
5         if not actions:
6             raise TypeError("The `actions` argument must be provided when "
7                             "calling `.as_view()` on a ViewSet. For example "
8                             "`.as_view({''get'': ''list''})`")
9       ······


能看到在actions字段可以设置 {''get'': ''list''} 这样的路由规则。

比如 urls.py 文件中配置:

my_product_list = ProductListViewSet.as_view({ ''get'': ''list'' })

另一种方法为创建 DefaultRouter 对象,然后用该对象注册 url。这种方法在工业中更被广泛地使用。

router = DefaultRouter()
router.register(r''product'', ProductListViewSet)

详见 Router 章节

ViewSetMixin 还有一个方法是initialize_request,这个方法主要是给 action 属性赋值,这个属性在设置动态 serializer 和 permission 的时候有很大的用处。

 

相关知识点 GenericViewSet:

GenericViewSet 类继承 GenericAPIView 和 ViewSetMixin,且提供了 get_object, get_queryset 方法以及其他的 generic view 的特征,但不会默认包括 action(所以需要通过继承特定类来实现)
在使用时必须重写该类,并且要么继承 mixin 类要么就自定义 action。

源码如下:

1 class GenericViewSet(ViewSetMixin, gernerics.GenericAPIView)
2     pass

由于 ViewSetMixin 类,这样继承了 GenericViewSet 的类就可以直接使用 router 对象配置 url 以及绑定 action。
由于 GenericAPIView 类, 这样继承了 GenericViewSet 的类就具有 queryset,serializer 以及 Pagination 的功能。

修改 views.py 文件:

1 class ProductListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
2     queryset = Product.objects.all()
3     serializer_class = ProductSerializer
4     pagination_class = ProductPagination

由于继承了 ListModelMixin 这样就自动有了 .list(request, *args, **kwargs) 的 action 方法。所以仅这段加上正确的 Router 配置,就可以实现展示商品 List 的效果。这也是它强于 GenericAPIView 的地方(即省略了 get -> list, post -> create 等函数的绑定)。

Extra 知识点 Routers:

由于 ViewSet 的 as_view() 方法,我们在 URL 配置时会简化很多操作,因为所有需要对 ViewSet 与 URL 的配置都可以使用 Router 类自动处理,这也使我们的代码变得更加规范。

例如:在 urls.py 文件中做下面操作:

 1 from rest_framework.routers import DefaultRouter
 2 
 3 router = DefaultRouter()
 4 router.register(r''products'', views.ProductListViewSet)
 5 
 6 urlpatterns = [
 7     url(r''^admin/'', admin.site.urls),
 8     url(r''^docs/'', include_docs_urls(title="My Project")),
 9     url(r''^api-auth/'', include(''rest_framework.urls'', namespace=''rest_framework'')),
10     url(r''^'', include(router.urls)),  # 所有在 router 对象上注册了的 ViewSet 都会被配置到 urlpatterns 中
11 ]

 在开发中 ViewSet 因为封装了大部分需要的操作,这些功能是它比 APIView 开发时更高效。一般只有在 ViewSet 的功能不够需要自定义一些特殊功能的时候,才会去自行编写稍微底层一点的 APIView 类。

关于Django Rest Framework和JSONField的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于1 Django REST Framework 开发 ---- 原生 Django View 热身、13 在 Django REST framework 善用 SerializerMethodField方法、2 Django REST Framework 开发 ---- APIView、4 Django REST Framework 开发 ---- ViewSet的相关信息,请在本站寻找。

本文标签: