Django-rest-framework (一)、序列化

朱雀 2022-05-28 04:45 318阅读 0赞

序列化

django-rest-framework serializer可以很方便的实现model对象的序列化,对前端传递的数据进行验证等等,功能与django原生的form很相似,但是却比form更强大,下面体验一下。

开始

安装:

  1. pip install django-rest-framework

创建一个新django项目:

  1. django-admin.py startproject rest
  2. python manage.py startapp snippet

rest/settings.py添加app:

  1. INSTALLED_APPS = (
  2. ...
  3. 'rest_framework',
  4. 'snippets',
  5. )

创建一个model
snippet/models.py:

  1. from django.db import models
  2. # Create your models here.
  3. LANGUAGE_CHOICES = (
  4. ('1', 'cn'),
  5. ('2', 'us')
  6. )
  7. STYLE_CHOICES = (
  8. ('1', 't1'),
  9. ('2', 't2')
  10. )
  11. class Snippet(models.Model):
  12. created = models.DateTimeField(auto_now_add=True)
  13. title = models.CharField(max_length=100,blank=True, default='')
  14. code = models.TextField()
  15. linenos = models.BooleanField(default=False)
  16. language = models.CharField(choices=LANGUAGE_CHOICES, default= '1',max_length=5)
  17. style = models.CharField(choices=STYLE_CHOICES, default='1',max_length=5)
  18. class Meta:
  19. ordering = ('created',)

创建serializer.py文件:
snippet/serializer.py:

  1. from rest_framework import serializers
  2. from snippet.models import Snippet,LANGUAGE_CHOICES,STYLE_CHOICES
  3. class Snippetserializer(serializers.Serializer):
  4. pk = serializers.IntegerField(read_only=True)
  5. title = serializers.CharField(required=False, allow_blank=True, max_length=32)
  6. code = serializers.CharField(style={
  7. 'base_template': 'textarea.html'})
  8. linenos = serializers.BooleanField(required=False)
  9. language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default= '1')
  10. style = serializers.ChoiceField(choices=STYLE_CHOICES, default='1')
  11. def create(self, validated_data):
  12. return Snippet.objects.create(**validated_data)
  13. def update(self, instance, validated_data):
  14. instance.title = validated_data.get('title', instance.title)
  15. instance.code = validated_data.get('code', instance.code)
  16. instance.linenos = validated_data.get('linenos', instance.linenos)
  17. instance.language = validated_data.get('language', instance.language)
  18. instance.style = validated_data.get('style', instance.style)
  19. instance.save()
  20. return instance

创建表结构:

  1. python manage.py makemigrations
  2. python manage.py migrate

开始使用django命令行,写一些序列化测试代码:

  1. $ python manage.py shell
  2. >>> from snippet.models import Snippet
  3. >>> from snippet.serializers import Snippetserializer
  4. >>> from rest_framework.renderers import JSONRenderer
  5. >>> from rest_framework.parsers import JSONParser
  6. >>>
  7. >>>
  8. >>> snippet= Snippet(code='foo="bar"\n')
  9. >>> snippet.save()
  10. >>> snippet= Snippet(code='print"hello,world"\n')
  11. >>> snippet.save()
  12. >>>> obj = Snippetserializer(snippet)
  13. >>> obj.data
  14. {'language': '1', 'pk': 2, 'title': '', 'code': 'print"hello,world"\n', 'linenos': False, 'style': '1'}
  15. >>> obj['code']
  16. <BoundField value=print"hello,world"
  17. errors=None>
  18. >>> content=JSONRenderer().render(obj.data)
  19. >>> stream = BytesIO(content)
  20. >>> content1 = JSONParser().parse(stream)
  21. >>> content2=JSONRenderer().render(obj.data).decode()
  22. >>> print(content)
  23. b'{
  24. "pk":2,"title":"","code":"print\\"hello,world\\"\\n","linenos":false,"language":"1","style":"1"}'
  25. >>> type(obj)
  26. <class 'snippet.serializers.Snippetserializer'>
  27. >>> type(obj.data)
  28. <class 'rest_framework.utils.serializer_helpers.ReturnDict'>
  29. >>> type(content)
  30. <class 'bytes'>
  31. >>> type(stream)
  32. <class '_io.BytesIO'>
  33. >>> content2=JSONRenderer().render(obj.data).decode()
  34. >>> type(content1)
  35. <class 'dict'>
  36. >>> type(content2)
  37. <class 'str'>
  38. >>> type(json.loads(content2))
  39. <class 'dict'>
  40. #可以看到,由rest serializer处理后的model对象变成了其的serializer对象,使用obj.data方法可以取出其内容,然后使用jsonrender方法将数据渲染成byte格式的json字符串,可以再通过bytesIO转换和通过jsonparser方法转换回dict格式。也可以直接在jsonrender的时候使用decode()方法处理,直接返回json格式str,然后通过json.loads()方法反序列化成dict格式。

同时,作为为django量身定制的框架,serializer也支持queryset的序列化(原生json模块不支持序列化queryset),在序列化的时候添加一个many = True参数即可:

  1. >>> serializer= Snippetserializer(Snippet.objects.all(),many=True)
  2. >>> serializer.data
  3. [OrderedDict([('pk', 1), ('title', ''), ('code', 'foo="bar"\n'), ('linenos', False), ('language', '1'), ('style', '1')]), OrderedDict([('pk', 2), ('title', ''), ('code', 'print"hello,world"\n'), ('linenos', False), ('language', '1'), ('style', '1')])]
  4. >>> serializer.data[0]
  5. OrderedDict([('pk', 1), ('title', ''), ('code', 'foo="bar"\n'), ('linenos', False), ('language', '1'), ('style', '1')])
  6. >>> serializer.data[0]['code']
  7. 'foo="bar"\n'

梳理一下:
1.model对象通过serializer方法序列化成新的对象obj,obj.data可以取出此对象的各items
2.jsonrender方法可以将obj.data渲染成byte格式对象,再通过byteIO处理可以转换成python的byte格式数据流。也可以decode成json风格str类型。
3.jsonparser方法可以将数据流(json风格str)反处理成dict格式

ModelSerializer

如modelform一样,restframework同样存在可以直接基于model关联,进行field字段关联验证等功能的模块,ModelSerializer.

改写snippet/serializer.py:

  1. from rest_framework import serializers
  2. from snippet.models import Snippet
  3. class SnippetSerializer(serializers.ModelSerializer):
  4. class Meta:
  5. model = Snippet
  6. fields = ('id','title','code','linenos','language','style')

写一个视图views.py,提供list查询、提交,单个对象查询、修改、删除方法:

  1. from django.http import HttpResponse
  2. from django.views.decorators.csrf import csrf_exempt
  3. from rest_framework.renderers import JSONRenderer
  4. from rest_framework.parsers import JSONParser
  5. from snippet.models import Snippet
  6. from snippet.serializers import SnippetSerializer
  7. class JSONResponse(HttpResponse):
  8. def __init__(self,data,**kwargs):
  9. content = JSONRenderer().render(data)
  10. kwargs['content_type'] = 'application/json'
  11. super(JSONResponse,self).__init__(content,**kwargs)
  12. @csrf_exempt
  13. def snippet_list(request):
  14. ''' List all code snippets, or create a new snippet. '''
  15. if request.method == 'GET':
  16. snippets = Snippet.objects.all()
  17. serializer = SnippetSerializer(snippets, many=True)
  18. return JSONResponse(serializer.data)
  19. elif request.method == 'POST':
  20. data = JSONParser().parse(request)
  21. serializer = SnippetSerializer(data=data)
  22. if serializer.is_valid():
  23. serializer.save()
  24. return JSONResponse(serializer.data,status=201)
  25. return JSONResponse(serializer.errors,status=400)
  26. @csrf_exempt
  27. def snippet_detail(request,pk):
  28. try:
  29. snippet = Snippet.objects.get(pk=pk)
  30. except Snippet.DoesNotExist:
  31. return HttpResponse(status=404)
  32. if request.method == 'GET':
  33. serializer = SnippetSerializer(snippet)
  34. return JSONResponse(serializer.data)
  35. elif request.method == 'PUT':
  36. data = JSONParser().parse(request)
  37. serializer = SnippetSerializer(snippet, data=data)
  38. if serializer.is_valid():
  39. serializer.save()
  40. return JSONResponse(serializer.data)
  41. return JSONResponse(serializer.errors, status=400)
  42. elif request.method == 'DELETE':
  43. snippet.delete()
  44. return HttpResponse(status=204)

定义urls规则关联视图函数:
urls.py:

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from snippet import views as snippet_views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^snippets/$',snippet_views.snippet_list),
  7. url(r'^snippets/detail/(?P<pk>[0-9]+)/$', snippet_views.snippet_detail),
  8. ]

验证测试:
开启服务:

  1. python manage.py runserver

测试:

  1. $ curl http://127.0.0.1:8000/snippets/
  2. [{
  3. "id":1,"title":"","code":"foo=\"bar\"\n","linenos":false,"language":"1","style":"1"},{
  4. "id":2,"title":"","code":"print\"hello,world\"\n","linenos":false,"language":"1","style":"1"}]ywq@ywq-ThinkPad-E470:/usr/local/myutils$ curl http://127.0.0.1:8000/snippets/detail/1
  5. $ curl http://127.0.0.1:8000/snippets/detail/1/
  6. {
  7. "id":1,"title":"","code":"foo=\"bar\"\n","linenos":false,"language":"1","style":"1"}

简单的接口OK了

发表评论

表情:
评论列表 (有 0 条评论,318人围观)

还没有评论,来说两句吧...

相关阅读

    相关 序列,反序列

    序列化: 对象的序列化主要有两种用途:   1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;   2) 在网络上传送对象的字节序列。   

    相关 Java序列

    所有分布式应用常常需要跨平台,跨网络,因此要求所有传的参数、返回值都必须实现序列化。 一、定义   序列化:把Java对象转换为字节序列的过程。