首先我们要知道常用的请求格式
- GET 127.0.0.1:8080/books/ # 获取所有数据, 返回值 [ { }, { } ]
- GET 127.0.0.1:8080/books/{ id } # 获取一条数据源,返回值 { }
- POST 127.0.0.1:8080/books/ # 新增一条数据, 返回值 : { }
- PUT 127.0.0.1:8080/books/{ id } # 修改数据,返回值 { }
- DELETE 127.0.0.1:8080/books/{ id } # 删除数据,返回空
序列化
表结构
from django.db import models # Create your models here. class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) # 外键字段 publish = models.ForeignKey(to="Publish", related_name="book", related_query_name="book_query", on_delete=models.CASCADE) # 多对多字段 authors = models.ManyToManyField(to="Author")
一
- get接口设计 - 导入模块
from rest_framework import serializers
- 建立一个序列化类
class BookSerializer(serializers.Serializer): 字段自定义
- 获取queryset
origin_data = Book.objects.all()
- 开始序列化
serialized_data - BookSerializer(origin_data , many= True)
- 获取序列化后的数据,返回给客户端
return Response(serialized_data.data)
注意:
- 外键字段,显示__str__方法的返回值
- 多对多字段需要自己动手获取数据
通过serializerMethodField() 方法
1 authors_list = serializers.SerializerMethodField() 2 3 def get_authors_list(self, book_obj): # 注意 该方法 必须get_+上述字段名 4 author_list = list() 5 6 for author in book_obj.authors.all(): 7 author_list.append(author.name) 8 9 return author_list
附上代码
- 视图
1 class BookView(APIView): 2 def get(self, request): 3 origin_data = Book.objects.all() 4 5 serialized_data = BookSerializer(origin_data, many=True) 6 7 return Response(serialized_data.data)
- app_serializers.py
class BookSerializer(serializers.Serializer): # nid = serializers.CharField(max_length=32) title = serializers.CharField(max_length=128) price = serializers.DecimalField(max_digits=5, decimal_places=2) publish = serializers.CharField() publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') # authors = serializers.CharField(max_length=32) # book_obj.authors.all() authors_list = serializers.SerializerMethodField() def get_authors_list(self, book_obj): author_list = list() for author in book_obj.authors.all(): author_list.append(author.name) return author_list
- post接口设计
视图
from rest_framework.views import APIView from rest_framework.response import Response class BookView(APIView): def get(self, request): origin_data = Book.objects.all() serialized_data = BookSerializer(origin_data, many=True) return Reponse(serialized_data.data) def post(self, request): verified_data = BookSerializer(data=request.data) if verified_data.is_valid(): book = verified_data.save() authors = Author.objects.filter(nid__in=request.data['authors']) book.authors.add(*authors) return Response(verified_data.data) else: return Response(verified_data.errors)
app_serializers.py
class BookSerializer(serializers.Serializer): # nid = serializers.CharField(max_length=32) title = serializers.CharField(max_length=128) price = serializers.DecimalField(max_digits=5, decimal_places=2) publish = serializers.CharField() publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') # authors = serializers.CharField(max_length=32) # book_obj.authors.all() authors_list = serializers.SerializerMethodField() def get_authors_list(self, book_obj): author_list = list() for author in book_obj.authors.all(): author_list.append(author.name) return author_list def create(self, validated_data): # {'title': 'Python666', 'price': Decimal('66.00'), 'publish': '2'} validated_data['publish_id'] = validated_data.pop('publish') book = Book.objects.create(**validated_data) return book
- get取一条数据接口,put接口, delete接口:
app_serializers.py不变
class BookFilterView(APIView): def get(self, request, nid): book_obj = Book.object.get(pk=nid) serialized_data = BookSerializer(book_obj, many=False) return Response(serialized_data.data) def put(self. request, nid): book_obj = Book.objects.get(pk=nid) verified_data = BookSerializer(data=request.data, instance=book_obj, many=False) if verified_data.is_valid(): verified_data.save() return Response(verified_data.data) else: return Response(verified_data.errors) def delete(self, request, nid): book_obj = Book.objects.get(pk=nid).delete()
二
你有没有发现如果使用serializers.Serializer会有如下问题:
- 需要手动插入数据(必须自定义create)
- 手动序列化需要的字段
实际上我们并不会用上述的这几种逻辑方式,因为drf已经帮我们封装好了
使用视图组件的mixin进行接口逻辑优化
让我们引入他们
from rest_framework.mixins import ( ListModelMixin CreateModelMixin DestroyModelMixin UpdateModelMixin RetrieveModelMinxin ) from rest_framework.generics import GenericAPIView
- app_serializers.py
from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = Book # 指定数据表 fields = ('title', # 显示字段 'price', 'publish', 'authors', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { # 只读字段 'publish': {'write_only': True}, 'authors': {'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') # 通过source 指定具体字段 , read_only也是只读 publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() # 多对多 def get_author_list(self, book_obj): # 拿到queryset开始循环 [{}, {}, {}, {}] authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors
- 视图
class BookView(ListModelView, CreateModelView, GenericAPIView): queryset = Book.objcets.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 BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, *args, **kwargs): return retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return update(request, *args, **kwargs) def delete(self, request, *args, **kwargs) return destroy(request, *args, **kwargs)
注意:单条数据操作的url是这样的:re_path(r'books/(?P<pk>d+)/$, views.BookFilterView.as_view())
三
第二点中的逻辑还可以进一步优化
通过视图组件的view进行接口优化
- 导入模块
from rest_framework import generics
- app_serializers.py同二
- 视图
class BookView(generics.ListCreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializer class BookFilterView(generics.RetrieveUpdateDestoryAPIView): queryset = Book.objects.all() serializer_class = BookSerializer
四
是不是觉得通过view进行优化已达极致,其实不然还有viewset,让我们一起来玩一玩
首先要想用viewset,我们就得重新设计urls
- urls
from django.urls import re_path from serializer import views urlpatterns = [ re_path(r'books/$', views.BookView.as_view({ 'get': 'list', 'post': 'create' })), re_path(r'books/(?P<pk>d+)/$', views.BookView.as_view({ 'get': 'retrieve', 'put': 'update', 'delete': 'destroy' })) ]
- app_serializers.py不变
- 视图
from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer