Django REST framework
Django 支持MTV模式, 前端渲染的内容,放在了后端 template中实施,包括获取数据,渲染模板一系列过程都在候选执行。
在前端能力强大的现在, 前后端分离开发模式已经成为主流, 所以后端只提供API, 于前端进行数据交互,成为业界主流。
此框架,就是在Django框架基础之上, 做了一层上层封装, 专门为后端API设计。
https://www.django-rest-framework.org/
Django REST framework is a powerful and flexible toolkit for building Web APIs.
Some reasons you might want to use REST framework:
- The Web browsable API is a huge usability win for your developers.
- Authentication policies including packages for OAuth1a and OAuth2.
- Serialization that supports both ORM and non-ORM data sources.
- Customizable all the way down - just use regular function-based views if you don't need the more powerful features.
- Extensive documentation, and great community support.
- Used and trusted by internationally recognised companies including Mozilla, Red Hat, Heroku, and Eventbrite.
Mini Demo Code
在django定义的 url 和 model基础之上
restframework 提供了 路由 序列化 视图集模块, 非常容易实现一个简单的应用。
https://www.django-rest-framework.org/
from django.urls import path, include from django.contrib.auth.models import User from rest_framework import routers, serializers, viewsets # Serializers define the API representation. class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ['url', 'username', 'email', 'is_staff'] # ViewSets define the view behavior. class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer # Routers provide an easy way of automatically determining the URL conf. router = routers.DefaultRouter() router.register(r'users', UserViewSet) # Wire up our API using automatic URL routing. # Additionally, we include login URLs for the browsable API. urlpatterns = [ path('', include(router.urls)), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) ]
Tutorial
Serialization
https://www.django-rest-framework.org/tutorial/1-serialization/#using-modelserializers
序列化工具中有个序列化类, 继承此类的类, 面向具体的model,定义序列化参数。
其功能是, 将 字符串的 数据格式, 转换为 plain 类型的python词典对象, 然后将此词典对象, 转换为ORM对象(django model), 再由ORM对象做持久化操作。
这是正向转换, 是client传送字符串格式数据到数据库中, 反向操作, 是将数据库中的数据转换为 字符串格式数据, 用于向客户端反馈。
The first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as
json
. We can do this by declaring serializers that work very similar to Django's forms. Create a file in thesnippets
directory namedserializers.py
and add the following.
模型定义
from django.db import models from pygments.lexers import get_all_lexers from pygments.styles import get_all_styles LEXERS = [item for item in get_all_lexers() if item[1]] LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()]) class Snippet(models.Model): created = models.DateTimeField(auto_now_add=True) title = models.CharField(max_length=100, blank=True, default='') code = models.TextField() linenos = models.BooleanField(default=False) language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100) style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) class Meta: ordering = ['created']
模型对应的序列化类, 可以发现,其中数据field的定义存在重复。
from rest_framework import serializers from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES class SnippetSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) title = serializers.CharField(required=False, allow_blank=True, max_length=100) code = serializers.CharField(style={'base_template': 'textarea.html'}) linenos = serializers.BooleanField(required=False) language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python') style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly') def create(self, validated_data): """ Create and return a new `Snippet` instance, given the validated data. """ return Snippet.objects.create(**validated_data) def update(self, instance, validated_data): """ Update and return an existing `Snippet` instance, given the validated data. """ instance.title = validated_data.get('title', instance.title) instance.code = validated_data.get('code', instance.code) instance.linenos = validated_data.get('linenos', instance.linenos) instance.language = validated_data.get('language', instance.language) instance.style = validated_data.get('style', instance.style) instance.save() return instance
模型的实例化, 并保存数据。
from snippets.models import Snippet from snippets.serializers import SnippetSerializer from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser snippet = Snippet(code='foo = "bar" ') snippet.save() snippet = Snippet(code='print("hello, world") ') snippet.save()
序列化类, 将模型转化为 普通的 python词典对象。
serializer = SnippetSerializer(snippet) serializer.data # {'id': 2, 'title': '', 'code': 'print("hello, world") ', 'linenos': False, 'language': 'python', 'style': 'friendly'}
使用工具, 将python词典对象, 转换为 字符串格式数据。
content = JSONRenderer().render(serializer.data) content # b'{"id": 2, "title": "", "code": "print(\"hello, world\")\n", "linenos": false, "language": "python", "style": "friendly"}'
反向操作, 将字符串数据,转换为普通的python 词典对象。
import io stream = io.BytesIO(content) data = JSONParser().parse(stream)
将词典对象, 传入序列化类, 做数据field合法性检查, 并保存到数据库。
serializer = SnippetSerializer(data=data) serializer.is_valid() # True serializer.validated_data # OrderedDict([('title', ''), ('code', 'print("hello, world") '), ('linenos', False), ('language', 'python'), ('style', 'friendly')]) serializer.save() # <Snippet: Snippet object>
使用 ModelSerializer 可以复用 model的数据field, 避免数据field重复定义。
class SnippetSerializer(serializers.ModelSerializer): class Meta: model = Snippet fields = ['id', 'title', 'code', 'linenos', 'language', 'style']
使用django view, 将正向和反向数据序列化串起来。
获取所有数据, 创建单个数据。
@csrf_exempt def snippet_list(request): """ List all code snippets, or create a new snippet. """ if request.method == 'GET': snippets = Snippet.objects.all() serializer = SnippetSerializer(snippets, many=True) return JsonResponse(serializer.data, safe=False) elif request.method == 'POST': data = JSONParser().parse(request) serializer = SnippetSerializer(data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, status=201) return JsonResponse(serializer.errors, status=400)
获取和修改和删除单个数据。
@csrf_exempt def snippet_detail(request, pk): """ Retrieve, update or delete a code snippet. """ try: snippet = Snippet.objects.get(pk=pk) except Snippet.DoesNotExist: return HttpResponse(status=404) if request.method == 'GET': serializer = SnippetSerializer(snippet) return JsonResponse(serializer.data) elif request.method == 'PUT': data = JSONParser().parse(request) serializer = SnippetSerializer(snippet, data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data) return JsonResponse(serializer.errors, status=400) elif request.method == 'DELETE': snippet.delete() return HttpResponse(status=204)
django function view注册到URLconf
from django.urls import path from snippets import views urlpatterns = [ path('snippets/', views.snippet_list), path('snippets/<int:pk>/', views.snippet_detail), ]