rest frame work 教程

来源:互联网 发布:汉化 知乎 编辑:程序博客网 时间:2024/05/14 17:10

1 Serialization

1.1 creating a model

snippets/models.py
from django.db import modelsfrom pygments.lexers import get_all_lexersfrom pygments.styles import get_all_stylesLEXERS = [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',)


1.2 creating a serializer class



serializers.py

from rest_framework import serializersfrom snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICESclass 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


1.3 working with serializer

python manage.py shell
from snippets.models import Snippetfrom snippets.serializers import SnippetSerializerfrom rest_framework.renderers import JSONRendererfrom rest_framework.parsers import JSONParsersnippet = Snippet(code='foo = "bar"\n')snippet.save()snippet = Snippet(code='print "hello, world"\n')snippet.save()
序列化:(data 是 Python native datatypes
serializer = SnippetSerializer(snippet)serializer.data# {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
content 是json字符串
content = JSONRenderer().render(serializer.data)content# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
Deserialization:(从输入流将数据解析为python native data)
from django.utils.six import BytesIOstream = BytesIO(content)data = JSONParser().parse(stream)
实例化为对象,并进行存储
serializer = SnippetSerializer(data=data)serializer.is_valid()# Trueserializer.validated_data# OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])serializer.save()# <Snippet: Snippet object>
序列化query-set(多个对象)
serializer = SnippetSerializer(Snippet.objects.all(), many=True)serializer.data# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]

1.4 using model serializers

修改(重构serializers.py)snippets/serializers.py
class SnippetSerializer(serializers.ModelSerializer):    class Meta:        model = Snippet        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
检查serializer instance 中的所有字段
from snippets.serializers import SnippetSerializerserializer = SnippetSerializer()print(repr(serializer))# SnippetSerializer():#    id = IntegerField(label='ID', read_only=True)#    title = CharField(allow_blank=True, max_length=100, required=False)#    code = CharField(style={'base_template': 'textarea.html'})#    linenos = BooleanField(required=False)#    language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...#    style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...


1.5 writing regular django using our serializer

Edit the snippets/views.py 
from django.http import HttpResponse, JsonResponsefrom django.views.decorators.csrf import csrf_exemptfrom rest_framework.renderers import JSONRendererfrom rest_framework.parsers import JSONParserfrom snippets.models import Snippetfrom snippets.serializers import SnippetSerialize
列出所有存在的snippet 和 创建新的snippet()
@csrf_exemptdef 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)
根据pk,对特定snippet做增删改@csrf_exemptdef 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)
chuang'jian the snippets/urls.py
from django.conf.urls import urlfrom snippets import viewsurlpatterns = [    url(r'^snippets/$', views.snippet_list),    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),]

1.6 teing our web API

测试 API using curl or httpie
pip install httpie
http http://127.0.0.1:8000/snippets/HTTP/1.1 200 OK...[  {    "id": 1,    "title": "",    "code": "foo = \"bar\"\n",    "linenos": false,    "language": "python",    "style": "friendly"  },  {    "id": 2,    "title": "",    "code": "print \"hello, world\"\n",    "linenos": false,    "language": "python",    "style": "friendly"  }]
http http://127.0.0.1:8000/snippets/2/HTTP/1.1 200 OK...{  "id": 2,  "title": "",  "code": "print \"hello, world\"\n",  "linenos": false,  "language": "python",  "style": "friendly"}

2 Request and response

2.1 Request object

request.POST  # Only handles form data.  Only works for 'POST' method.request.data  # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.
return Response(data)  # Renders to content type as requested by the client.

2.2 Response Object

2.3 Status codes

2.4 Wrapping API views(class based views andfunction based views)

  1. The @api_view decorator for working with function based views.
  2. The APIView class for working with class-based views.

2.5 pulling it all together(将以上四点结合使用)

from rest_framework import statusfrom rest_framework.decorators import api_viewfrom rest_framework.response import Responsefrom snippets.models import Snippetfrom snippets.serializers import SnippetSerializer@api_view(['GET', 'POST'])def snippet_list(request):    """    List all snippets, or create a new snippet.    """    if request.method == 'GET':        snippets = Snippet.objects.all()        serializer = SnippetSerializer(snippets, many=True)        return Response(serializer.data)    elif request.method == 'POST':        serializer = SnippetSerializer(data=request.data)        if serializer.is_valid():            serializer.save()            return Response(serializer.data, status=status.HTTP_201_CREATED)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])def snippet_detail(request, pk):    """    Retrieve, update or delete a snippet instance.    """    try:        snippet = Snippet.objects.get(pk=pk)    except Snippet.DoesNotExist:        return Response(status=status.HTTP_404_NOT_FOUND)    if request.method == 'GET':        serializer = SnippetSerializer(snippet)        return Response(serializer.data)    elif request.method == 'PUT':        serializer = SnippetSerializer(snippet, data=request.data)        if serializer.is_valid():            serializer.save()            return Response(serializer.data)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)    elif request.method == 'DELETE':        snippet.delete()        return Response(status=status.HTTP_204_NO_CONTENT)

2.6 Adding optional format suffixes to our URLs

1.增加关键参数 format
def snippet_list(request, format=None):
def snippet_list(request, format=None):
2.更新urls.py,,在已经存在的文件上追加 format_suffix_patterns
from django.conf.urls import urlfrom rest_framework.urlpatterns import format_suffix_patternsfrom snippets import viewsurlpatterns = [    url(r'^snippets/$', views.snippet_list),    url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),]urlpatterns = format_suffix_patterns(urlpatterns)

2.7 How is looking that

http http://127.0.0.1:8000/snippets/HTTP/1.1 200 OK...[  {    "id": 1,    "title": "",    "code": "foo = \"bar\"\n",    "linenos": false,    "language": "python",    "style": "friendly"  },  {    "id": 2,    "title": "",    "code": "print \"hello, world\"\n",    "linenos": false,    "language": "python",    "style": "friendly"  }]
控制response得到的数据类型  using the Accept header:
http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSONhttp http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML
Or by appending a format suffix:
http http://127.0.0.1:8000/snippets.json  # JSON suffixhttp http://127.0.0.1:8000/snippets.api   # Browsable API suffix
控制发送的请求的类型 using the Content-Type header.
# POST using form datahttp --form POST http://127.0.0.1:8000/snippets/ code="print 123"{  "id": 3,  "title": "",  "code": "print 123",  "linenos": false,  "language": "python",  "style": "friendly"}# POST using JSONhttp --json POST http://127.0.0.1:8000/snippets/ code="print 456"{    "id": 4,    "title": "",    "code": "print 456",    "linenos": false,    "language": "python",    "style": "friendly"}

3 class based views

3.1 rewriting our API using class based views

views.py进行重构

from snippets.models import Snippetfrom snippets.serializers import SnippetSerializerfrom django.http import Http404from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import statusclass SnippetList(APIView):    """    List all snippets, or create a new snippet.    """    def get(self, request, format=None):        snippets = Snippet.objects.all()        serializer = SnippetSerializer(snippets, many=True)        return Response(serializer.data)    def post(self, request, format=None):        serializer = SnippetSerializer(data=request.data)        if serializer.is_valid():            serializer.save()            return Response(serializer.data, status=status.HTTP_201_CREATED)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class SnippetDetail(APIView):    """    Retrieve, update or delete a snippet instance.    """    def get_object(self, pk):        try:            return Snippet.objects.get(pk=pk)        except Snippet.DoesNotExist:            raise Http404    def get(self, request, pk, format=None):        snippet = self.get_object(pk)        serializer = SnippetSerializer(snippet)        return Response(serializer.data)    def put(self, request, pk, format=None):        snippet = self.get_object(pk)        serializer = SnippetSerializer(snippet, data=request.data)        if serializer.is_valid():            serializer.save()            return Response(serializer.data)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)    def delete(self, request, pk, format=None):        snippet = self.get_object(pk)        snippet.delete()        return Response(status=status.HTTP_204_NO_CONTENT)

refactor url.py

from django.conf.urls import urlfrom rest_framework.urlpatterns import format_suffix_patternsfrom snippets import viewsurlpatterns = [    url(r'^snippets/$', views.SnippetList.as_view()),    url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),]urlpatterns = format_suffix_patterns(urlpatterns)


3.2 Using mixins
3.3 using generic class-based views


4 Authentication and permissions


4.1 Adding informations to our models
4.2 Adding endpoints for our user models
4.3 Associating snippet with users
4.4 updating our serializer
4.5 Adding required permission to views
4.6 Adding login to the Browsable API
4.7 Objects level permissions
4.8 Authenticating with the API

5 Relationships and hyperlinked APIS