第四章 restframework——视图组件

第四章 restframework——视图组件

一、基本视图

二、mixin模块+generics模块(GenericAPIView类)编写视图

三、generics模块下的ListCreateAPIView,RetrieveUpdateDestroyAPIView

四、viewsets模块下的ModelViewSet

一、基本视图

 回顾上一章节的序列化组件,你会发现views里的代码逻辑部分大同小异

代码如下:

from django.db import models

# Create your models here.
from django.db import models

# Create your models here.


class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish")
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    # def __str__(self):
    #     return self.name

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name
models.py

urls.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publishes/$',views.PublishView.as_view()),
    url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),
    url(r'^books/$',views.BookView.as_view()),
    url(r'^books/(d+)/$',views.BookDetailView.as_view())
]
from django.shortcuts import *
from django.views import View
from .models import *
import json
# Create your views here.

from rest_framework.views import APIView
from rest_framework.response import Response
from .all_serializers import *

# class BookSerializers(serializers.Serializer):
#     title = serializers.CharField(max_length=32)
#     price = serializers.IntegerField()
#     pub_date = serializers.DateField()
#     publish = serializers.CharField(source="publish.name")
#     # authors=serializers.CharField(source="authors.all") #这样会返回queryset对象,看起来还不是特别舒服
#     authors = serializers.SerializerMethodField() # 这个方法只是为多对多服务的,下面要写类似钩子的方法
#     def get_authors(self,obj):
#         temp = []
#         for obj in obj.authors.all():
#             temp.append(obj.name)
#         return temp

class BookView(APIView):
    def get(self,request):
        # get请求数据
        book_list = Book.objects.all()
        bs = BookModelSerializers(book_list,many=True)
        '''
        序列化BookSerializers(book_list,many=True)做了如下操作:
        temp = []
        for obj in book_list:
            temp.append({
                "title":obj.title,
                "price":obj.price,
                "pub_date":obj.pub_date,
                "publish":obj.publish,   # 这里的返回值就是上面get_authors的返回值
            })                  
        '''
        return Response(bs.data)

    def post(self,request):
        # post请求数据
        bs = BookModelSerializers(data=request.data)
        if bs.is_valid():
            print(bs.validated_data)
            bs.save()  # create方法
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class BookDetailView(APIView):
    def get(self,request,id):
        book = Book.objects.filter(pk=id).first()
        bs = BookModelSerializers(book)
        return Response(bs.data)
    def put(self,request,id):
        book = Book.objects.filter(pk=id).first()
        # 因为是做更新操作,所以要写data=request.data,把新数据放进去
        bs = BookModelSerializers(book,data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)
    def delete(self,request,id):
        Book.objects.filter(pk=id).delete()
        # 删除操作返回空即可
        return Response()


class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ps = PublishModelSerializers(publish_list, many=True)
        return Response(ps.data)
        # 取数据
        # print('restframework', request.data)
        # print('restframework type', type(request.data))
        # print('restframework', request._request.GET)
        # print('restframework type', type(request._request.GET))
        # print('restframework', request.GET)
        # print('restframework type', type(request.GET))
        # return HttpResponse('ok')
        # 序列化
        # publish_list = Publish.objects.all()    #queryset对象
        # pb = PublishSerializers(publish_list, many=True)
        # many = true 代表前面传入的参数是queryset对象
        # print(pb.data)

        # publish1 = Publish.objects.filter(pk=1).first()
        # print(publish1)        # publish对象
        # pb = PublishSerializers(publish1,many=False)
        # PublishSerializers(model_obj,many = false)
        # many = false 代表前面传入的参数是model对象
        # 默认many = false,所以如果是model对象可以不用写many
        # print(pb.data)
        # return HttpResponse(pb.data)

        # 方式一
        # publish_list = list(Publish.objects.all().values('name','email'))
        # return HttpResponse(json.dumps(publish_list))
        # 方式二
        # from django.forms.models import model_to_dict
        # publish_list = Publish.objects.all()
        # temp = []
        # for obj in publish_list:
        #     temp.append(model_to_dict(obj))
        # return HttpResponse(json.dumps(temp))
        # 方式三
        # from django.core import serializers
        # publish_list = Publish.objects.all()
        # temp = serializers.serialize("json",publish_list)
        # return HttpResponse(temp)

    def post(self, request):
        # 取数据
        # 原生的request操作
        # print('POST',request.POST)
        # print('body',request.body)
        # print(type(request))
        # from django.core.handlers.wsgi import WSGIRequest
        # print(request.data)
        # 新的request支持的操作
        # 要想使用之前request的方法
        # ret = request._request.POST
        # django将request的所有方法的数据获取进行了不同的封装
        # 而restframework将request下POST方法的数据封装成request.data
        # print('restframework',request.data)
        # print('restframework type',type(request.data))
        # return HttpResponse('post')
        ps = PublishModelSerializers(data=request.data)
        if ps.is_valid():
            print(ps.validated_data)
            ps.save()  # create方法
            return Response(ps.data)
        else:
            return Response(ps.errors)


class PublishDetailView(APIView):
    def get(self, request, pk):

        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish)
        return Response(ps.data)

    def put(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish, data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

    def delete(self, request, pk):
        Publish.objects.filter(pk=pk).delete()
        return Response()
views.py
from rest_framework import serializers
from .models import *

# 为queryset,model对象做序列化
# class PublishSerializers(serializers.Serializer):
#     # 下面写的字段取决于你需要哪些字段做序列化
#     name = serializers.CharField()
#     email = serializers.CharField()

class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model=Publish
        fields="__all__"


class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book # 表名
        fields = "__all__" # 默认把所有字段写入,不包括自己写的get_authors方法
        # field = ['nid','title','authors','publish'] # 指定字段
        # exclude = ('nid')  # 除了...字段,不能跟fields同时用
        # depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
    # 如果要指定一对多,或多对多显示的字段需要重写create方法
    publish = serializers.CharField(source='publish.pk')
    authors = serializers.CharField(source="authors.all")
    def create(self, validated_data):
        # print('validated_data',validated_data)
        book = Book.objects.create(
            title=validated_data['title'],
            price=validated_data['price'],
            pub_date=validated_data['pub_date'],
            publish_id=validated_data['publish']['pk']
        )
        book.authors.add(*validated_data['authors'])
        return book
all_serializers.py

二、mixin模块+generics模块(GenericAPIView类)编写视图

尝试用mixin类写一个AuthorView,对比下它的简便。

【mixin模块】

导入模块

from rest_framework import mixins

先简单熟悉下mixin模块下的几个class,它对应了restful的规范

查看下ListModeMixin的源码,与之前写的get方法对应起来看下

查看下CreateModeMixin的源码,与之前写的get方法对应起来看下

其他的将不再做对比,你会发现其实restframework替我们做了功能封装避免重复代码,那我们用mixin尝试写AuthorView看看

urls.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^authors/$',views.AuthorView.as_view(),name='authors'),
    url(r'^authors/(?P<pk>d+)/$',views.AuthorDetailView.as_view(),name='author_detail'),

    url(r'^publishes/$',views.PublishView.as_view(),name='publishes'),
    url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),

    url(r'^books/$',views.BookView.as_view(),name='books'),
    url(r'^books/(d+)/$',views.BookDetailView.as_view(),name='book_detail'),
]

all_serializers.py

class AuthorModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = "__all__"

 【generics模块

 导入模块

from rest_framework import generics

views.py

注意:

①类必须继承generics.GenericAPIView

②切记:queryset和serializer_class 这两个名字不能改,固定写法,否则会出现如下报错

AssertionError: 'AuthorView' should either include a `queryset` attribute, or override the `get_queryset()` method.

from rest_framework import mixins
from rest_framework import generics

class AuthorView(
        mixins.ListModelMixin,
        mixins.CreateModelMixin,
        generics.GenericAPIView
    ):
    # GenericAPIView继承了之前的APIView
    # !!!切记:queryset和serializer_class 这两个名字不能改!!!
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers
    def get(self,request,*args,**kwargs):
        return self.list(request,*args,**kwargs)
    def post(self,request,*args,**kwargs):
        return self.create(request,*args,**kwargs)

class AuthorDetailView(
        mixins.RetrieveModelMixin,
        mixins.DestroyModelMixin,
        mixins.UpdateModelMixin,
        generics.GenericAPIView
    ):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers
    def get(self,request,*args,**kwargs):
        return self.retrieve(request,*args,**kwargs)
    def put(self,request,*args,**kwargs):
        return self.update(request,*args,**kwargs)
    def delete(self,request,*args,**kwargs):
        return self.destroy(request,*args,**kwargs)

四、generics模块下的ListCreateAPIView,RetrieveUpdateDestroyAPIView

上面我们看了mixin模块及generics模块的确节省了大量代码,可是还是存在重复代码,此时我们再来看下generics模块下的类们。

通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。

还是用author举例:

导入模块

from rest_framework import generics

views.py

class AuthorView(generics.ListCreateAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

对比下看看

五、viewsets模块下的ModelViewSet

像上面所述,还是有重复代码,别急,还有更简便的。

记住核心在于,利用字典的形式指定请求方法(get、post...)的操作(list,create....)

导入模块

from rest_framework import viewsets

urls.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    # url(r'^authors/$',views.AuthorView.as_view(),name='authors'),
    # url(r'^authors/(?P<pk>d+)/$',views.AuthorDetailView.as_view(),name='author_detail'),

    url(r'^authors/$',views.AuthorModelView.as_view({"get":"list","post":"create"}),name='authors'),
    url(r'^authors/(?P<pk>d+)/$',views.AuthorModelView.as_view({
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            }),name='author_detail'),

    url(r'^publishes/$',views.PublishView.as_view(),name='publishes'),
    url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),

    url(r'^books/$',views.BookView.as_view(),name='books'),
    url(r'^books/(d+)/$',views.BookDetailView.as_view(),name='book_detail'),
]

views.py

from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

如果你想用自己方法来处理请求,只需自己重写函数,并更改路由即可

原文地址:https://www.cnblogs.com/neymargoal/p/9791004.html