这篇文章主要围绕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
- 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
给定具有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 热身
在正式开始 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数据类型调取数据的过程就完成了,但是会有以下问题:
- 图片,日期格式支持不够(仅会显示图片相对路径)
- 主键JSON字段之外,使得调用起来会不方便
- 文档需要手动写,缺乏规范性且效率低下
- 输入验证缺失 (类似于表单的认证)
- 等等
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
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
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的相关信息,请在本站寻找。
本文标签: