django rest

djangorest框架是今天看的一个文档。
比较简单的是入门篇,
https://github.com/moocstudent/django-proj
这个呢就是根据入门篇来的代码,
其中比django原教程多的就是关于深入的rest框架的关键点使用。

from django.shortcuts import render

from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from rest_framework import permissions
from tutorial.quickstart.serializers import UserSerializer, GroupSerializer

# Rather than write multiple views we're grouping together all the common behavior into classes called ViewSets.
class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
    permission_classes = [permissions.IsAuthenticated]


class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    permission_classes = [permissions.IsAuthenticated]

比如下面这里的ModelViewSet就是一个通用的restful接口组件,

from django.contrib.auth.models import User, Group
from rest_framework import serializers

# Notice that we're using hyperlinked relations in this case with HyperlinkedModelSerializer.
# You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
class UserSerializer(serializers.HyperlinkedModelSerializer):
    # meta data set
    class Meta:
        model = User
        # custom fields
        fields = ['url', 'username', 'email', 'groups']


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ['url', 'name']

再比如serializer序列化,这个序列化类在view层进行了指定。
最后接口的路由是通过urls配置的:

from django.urls import include, path
from rest_framework import routers
from tutorial.quickstart import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

# 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'))
]

整理也就是说前端请求过来之后通过urls找到相应接口路由,
再找到视图views,然后处理相关逻辑,而serializer类似一个处理单元。
在serializer中,原本配置比较多

from rest_framework import serializers
import snippets.models


class SnippetSerializer(serializers.ModelSerializer):
    # 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')

    class Meta:
        model = Snippet
        fields = ['id','title','code','linenos','language','style']

   #  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

如果上面第一行是class SnippetSerializer(serializers.Serializer)的话对应注释代码也是
配合serializers.Serializer的,而ModelSerializer则提供了通用的方法。

好吧趁热打铁,执行python manage.py shell进入shell模式:

IPython 7.25.0 -- An enhanced Interactive Python. Type '?' for help.

   ...: from snippets.serializers import SnippetSerializer
   ...: from rest_framework.renderers import JSONRenderer
   ...: from rest_framework.parsers import JSONParser
   ...: 
   ...: snippet = Snippet(code='foo = "bar"\n')
   ...: snippet.save()
   ...: 
   ...: snippet = Snippet(code='print("hello, world")\n')
   ...: snippet.save()

In [2]: serializer = SnippetSerializer(snippet)
   ...: serializer.data
Out[2]: {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}

In [3]: content = JSONRenderer().render(serializer.data)
   ...: content
Out[3]: b'{"id":2,"title":"","code":"print(\\"hello, world\\")\\n","linenos":false,"language":"python","style":"friendly"}'

In [4]: import io
   ...: 
   ...: stream = io.BytesIO(content)
   ...: data = JSONParser().parse(stream)

In [5]: serializer = SnippetSerializer(data=data)
   ...: serializer.is_valid()
Out[5]: True

In [6]: serializer.validated_data
Out[6]: 
OrderedDict([('title', ''),
             ('code', 'print("hello, world")'),
             ('linenos', False),
             ('language', 'python'),
             ('style', 'friendly')])

In [7]: serializer.save()
Out[7]: <Snippet: Snippet object (3)>

下载pip里的httpie请求查看:

HTTP/1.1 200 OK
Content-Length: 354
Content-Type: application/json
Date: Wed, 11 Jan 2023 12:36:47 GMT
Server: WSGIServer/0.2 CPython/3.9.9
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "code": "foo = \"bar\"\n",
        "id": 1,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    },
    {
        "code": "print(\"hello, world\")\n",
        "id": 2,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    },
    {
        "code": "print(\"hello, world\")",
        "id": 3,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    }
]

同样的,如果请求有不同的url格式,django restframework也是支持的,
如:

http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML
http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # Browsable API suffix

而实现如上操作应该在接口定义format=None

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk, format=None):

而None表示默认值。
同样在urls中加入format_suffix_patterns:

from django.urls import path
from snippets import views
from rest_framework.urlpatterns import format_suffix_patterns


urlpatterns = [
    path('snippets/', views.snippet_list),
    path('snippets/<int:pk>/', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

在接口请求方面,django restframework提供了非常多的方式,
https://github.com/moocstudent/tutorial
比如RetrieveUpdateDestroyAPIView提供了获取一个数据详情,
更新以及删除的相关简便操作。

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics

"""
Using the mixin classes we've rewritten the views to use slightly less code than before, 
but we can go one step further. REST framework provides a set of already mixed-in generic 
views that we can use to trim down our views.py module even more.
"""

"""
List all code snippets, or create a new snippet.
"""
class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

"""
Retrieve, update or delete a code snippet.
"""
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
posted @ 2023-01-11 20:23  ukyo--碳水化合物  阅读(56)  评论(0)    收藏  举报