Django REST framework 初识
一、官网快速实例
# 安装 RESTful pip install djangorestframework
二、序列化
models.py
from django.db import models class Author(models.Model): name = models.CharField(max_length=32, verbose_name="作者") age = models.IntegerField(verbose_name="年龄") def __str__(self): return self.name class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name="出版社") email = models.EmailField(verbose_name="邮箱") address = models.CharField(max_length=128, verbose_name="地址") def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=32, verbose_name="书名") price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="价格") publish_date = models.DateField(verbose_name="出版日期") # 与Publish建立一对多的关系,外键字段一般建立在多的一方 publisher = models.ForeignKey(to="Publisher", verbose_name="出版社") # 与Author表建立多对多的关系,ManyToManyField通常设置在正向查询多的那一边,自动创建第三张表 authors = models.ManyToManyField(to="Author", verbose_name="作者") def __str__(self): return self.title
urls.py
from django.conf.urls import url from appxx import views urlpatterns = [ url(r"^publishers/$", views.PublisherList.as_view()), url(r"^publishers/(\d+)$", views.PublisherDetail.as_view()), url(r"^books/$", views.BookList.as_view()), url(r"^books/(\d+)$", views.BookDetail.as_view()), ]
views.py
铺垫:
from django.shortcuts import HttpResponse from django.views import View from appxx import models from django.forms.models import model_to_dict from django.core import serializers class PublisherList(View): def get(self, request): """取数据""" # 方式一: publisher_list = models.Publisher.objects.all().values("name", "email", "address") return HttpResponse(publisher_list) # 方式二: publisher_list = models.Publisher.objects.all() temp = [] for obj in publisher_list: temp.append(model_to_dict(obj)) return HttpResponse(temp) # 方式三: publisher_list = models.Publisher.objects.all() data = serializers.serialize("json", publisher_list) return HttpResponse(data) def get(self, request): pass
RESTful 的 Serializer
Publisher表(没有一对多和多对多字段)
from appxx import models from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers class PublisherSerializer(serializers.Serializer): name = serializers.CharField(max_length=32) email = serializers.EmailField() address = serializers.CharField(max_length=128) def create(self, validated_data): # 根据提供的验证过的数据创建并返回一个新的"Publisher"实例 return models.Publisher.objects.create(**validated_data) def update(self, instance, validated_data): # 根据提供的验证过的数据更新并返回一个已经存在的"Publisher"实例 instance.name = validated_data.get("name", instance.name) instance.email = validated_data.get("email", instance.email) instance.address = validated_data.get("address", instance.address) instance.save() return instance class PublisherList(APIView): def get(self, request): publisher_list = models.Publisher.objects.all() s = PublisherSerializer(publisher_list, many=True) return Response(s.data) def post(self, request): s = PublisherSerializer(data=request.data) if s.is_valid(): s.save() return Response(s.data) return Response(s.errors) class PublisherDetail(APIView): def get(self, request, pk): publisher = models.Publisher.objects.filter(pk=pk).first() s = PublisherSerializer(publisher) return Response(s.data) def put(self, request, pk): publisher = models.Publisher.objects.filter(pk=pk).first() s = PublisherSerializer(publisher, data=request.data) if s.is_valid(): s.save() return Response(s.data) return Response(s.errors) def delete(self, request, pk): models.Publisher.objects.filter(pk=pk).delete() return Response("删除成功")
RESTful 的 ModelSerializer
Book表(有一对多和多对多字段)
备注说明:ModelSerializer继承Serializer;如果一对多字段中有参数source,post提交数据时 --> 则需要重写save中的create方法;除此之外,对于多对多字段,如果使用下面的方法请求(get)数据,将会得到更直观的数据,但这里并没有解决post、put请求操作。
class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" # fields = ("title", "price", "publish_date", "publisher", "authors") # 一对多,通过source="本张表一对多字段.关联的表的任一字段",即可获取到对应的数据;如果不写,则获取到的是pk值 publisher = serializers.CharField(source="publisher.name") # 多对多,通过source="本张表多对多字段.all",获取到的是 QuerySet 数据;如果不写,则获取到的是pk值 # authors = serializers.CharField(source="authors.all") # 多对多,还可以用下面的方法获取到关联的数据 # authors = serializers.SerializerMethodField() # def get_authors(self, obj): # 格式:get_多对多字段名(self, obj) # temp = [] # for author in obj.authors.all(): # temp.append(author.name) # return temp # 重写save中的create方法 def create(self, validated_data): obj = models.Book.objects.create( title=validated_data["title"], price=validated_data["price"], publish_date=validated_data["publish_date"], publisher_id=validated_data["publisher"]["name"], ) obj.authors.add(*validated_data["authors"]) return obj class BookList(APIView): def get(self, request): # 获取书籍列表 book_list = models.Book.objects.all() s = BookSerializer(book_list, many=True) return Response(s.data) def post(self, request): # 新增书籍 s = BookSerializer(data=request.data) if s.is_valid(): s.save() # 实际执行的是create()方法 return Response(s.data) return Response(s.errors) class BookDetail(APIView): def get(self, request, pk): # 获取某本书籍 book = models.Book.objects.filter(pk=pk).first() s = BookSerializer(book) return Response(s.data) def put(self, request, pk): # 修改某本书籍 book = models.Book.objects.filter(pk=pk).first() s = BookSerializer(book, data=request.data) if s.is_valid(): s.save() # 实际执行的是update()方法 return Response(s.data) return Response(s.errors) def delete(self, request, pk): # 删除某本书籍 models.Book.objects.filter(pk=pk).delete() return Response("删除成功")
超链接API:HyperlinkedModelSerializer(继承ModelSerializer)
class BookSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = models.Book fields = "__all__" publisher = serializers.HyperlinkedIdentityField( view_name="publisher_detail", lookup_field="publisher_id", lookup_url_kwarg="pk" ) class BookList(APIView): def get(self, request): book_list = models.Book.objects.all() s = BookSerializer(book_list, many=True, context={"request": request}) return Response(s.data) class BookDetail(APIView): def get(self, request, pk): book = models.Book.objects.filter(pk=pk).first() s = BookSerializer(book, context={"request": request}) return Response(s.data)
urls.py部分:
from django.conf.urls import url from appxx import views urlpatterns = [ url(r"^publishers/$", views.PublisherList.as_view(), name="publisher_list"), url(r"^publishers/(?P<pk>\d+)/$", views.PublisherDetail.as_view(), name="publisher_detail"), url(r"^books/$", views.BookList.as_view(), name="book_list"), url(r"^books/(\d+)/$", views.BookDetail.as_view(), name="book_detail"), ]
则获取到的数据,相应字段将改为超链接:
三、使用mixins
# views.py
from appxx import models from rest_framework import serializers from rest_framework import mixins from rest_framework import generics class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" class BookList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = models.Book.objects.all() serializer_class = BookSerializer 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 BookDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = models.Book.objects.all() serializer_class = BookSerializer 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)
# urls.py
urlpatterns = [ url(r"^books/$", views.BookList.as_view(), name="book_list"), url(r"^books/(?P<pk>\d+)/$", views.BookDetail.as_view(), name="book_detail"), ]
四、使用基于类的通用视图
# views.py
from appxx import models from rest_framework import serializers from rest_framework import generics class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" class BookList(generics.ListCreateAPIView): queryset = models.Book.objects.all() serializer_class = BookSerializer class BookDetail(generics.RetrieveUpdateDestroyAPIView): queryset = models.Book.objects.all() serializer_class = BookSerializer
# urls.py
urlpatterns = [ url(r"^books/$", views.BookList.as_view(), name="book_list"), url(r"^books/(?P<pk>\d+)/$", views.BookDetail.as_view(), name="book_detail"), ]
五、ViewSet
使用ViewSet重构:
from appxx import models from rest_framework import serializers from rest_framework import viewsets class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" class BookViewSet(viewsets.ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookSerializer
将ViewSet明确绑定到URL:
from django.conf.urls import url from appxx import views urlpatterns = [ url(r"^books/$", views.BookViewSet.as_view({ "get": "list", "post": "create"}), name="book_list"), url(r"^books/(?P<pk>\d+)/$", views.BookViewSet.as_view({ "get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}), name="book_detail"), ]
将URL整理一下:
from django.conf.urls import url from appxx import views book_list = views.BookViewSet.as_view({ "get": "list", "post": "create"}) book_detail = views.BookViewSet.as_view({ "get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}) urlpatterns = [ url(r"^books/$", book_list, name="book_list"), url(r"^books/(?P<pk>\d+)/$", book_detail, name="book_detail"), ]
六、使用路由器
from django.conf.urls import url, include from appxx import views from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r"books", views.BookViewSet) router.register(r"publishers", views.PublisherViewSet) urlpatterns = [ url(r"", include(router.urls)), ]