基类,子序列化、多表序列化与反序列化
# 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的 class BaseModel(models.Model): is_delete = models.BooleanField(default=False) updated_time = models.DateTimeField(auto_now_add=True) class Meta: abstract = True # 必须完成该配置
class Book(BaseModel): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=5, decimal_places=2, null=True) image = models.ImageField(upload_to='img', default='img/default.png') publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING) authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False) class Publish(BaseModel): name = models.CharField(max_length=64) class Author(BaseModel): name = models.CharField(max_length=64) class AuthorDetail(BaseModel): phone = models.CharField(max_length=11) author = models.OneToOneField( to=Author, related_name='detail', db_constraint=False, on_delete=models.SET_NULL, null=True )
class AuthorModelSerializer(serializers.ModelSerializer): class Meta: model = models.Author # 不常用,将全部字段提供给外界 fields = '__all__' # ------------------------------------------------------------------ class AuthorModelSerializer(serializers.ModelSerializer): class Meta: model = models.Author # 不常用,排除指定字段的其他所有字段,不能自动包含 外键反向 字段 exclude = ['is_delete', 'updated_time'] # ------------------------------------------------------------------ class AuthorModelSerializer(serializers.ModelSerializer): class Meta: model = models.Author # 'detail', 'books' 是 外键(正向|反向) 字段 fields = ['name', 'detail', 'books'] # 不常用,自动深度,自动深度会显示外键关联表的所有字段 depth = 2 # 正向外键字段:就是外键的属性名 # 反向外键字段:就是外键属性设置的related_name
1)子序列化的字段,必须是 外键(正向|反向) 字段
2)子序列化对应的数据是单个many=False,数据对应是多个many=True
3)子序列化其实就是自定义序列化字段,覆盖了原有 外键(正向|反向)字段 的规则,所以不能进行反序列化
url(r'^authors/$', views.AuthorAPIView.as_view()), url(r'^authors/(?P<pk>\d+)/$', views.AuthorAPIView.as_view())
from rest_framework import serializers from . import models class AuthorDetailModelSerializer(serializers.ModelSerializer): class Meta: model = models.AuthorDetail fields = ['phone'] class BookModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ['name', 'price'] class AuthorModelSerializer(serializers.ModelSerializer): # 子序列化:子序列化类必须写在上方,且只能对 外键(正向反向)字段 进行覆盖 # 注:运用了子序列化的外键字段,就不能进行数据库的反序列化过程 detail = AuthorDetailModelSerializer(many=False, read_only=True) books = BookModelSerializer(many=True, read_only=True) # 问题: # 1)不设置read_only时,就相当于允许反序列化,反序列化是就会报错 # 2)设置read_only时,可以完成反序列化,但是新增的数据再序列化了,就没有外键关联的数据,与原来数据格式就不一致了 class Meta: model = models.Author fields = ['name', 'detail', 'books']
# 实际开发,资源的大量操作都是查询操作,只有查需求的资源,可以采用子序列化 class AuthorAPIView(APIView): def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: obj = models.Author.objects.filter(is_delete=False, pk=pk).first() serializer = serializers.AuthorModelSerializer(instance=obj) return APIResponse(result=serializer.data) else: queryset = models.Author.objects.filter(is_delete=False).all() serializer = serializers.AuthorModelSerializer(instance=queryset, many=True) return APIResponse(results=serializer.data) # 测试子序列化外键字段,不能参与反序列化,因为 def post(self, request, *args, **kwargs): serializer = serializers.AuthorModelSerializer(data=request.data) if serializer.is_valid(): obj = serializer.save() return APIResponse(result=serializers.AuthorModelSerializer(instance=obj).data, http_status=201) else: # 校验失败 => 异常响应 return APIResponse(1, serializer.errors, http_status=400)
url(r'^books/$', views.BookAPIView.as_view()), url(r'^books/(?P<pk>\d+)/$', views.BookAPIView.as_view()),
models.py
class Book(BaseModel): # ... @property # @property字段默认就是read_only,且不允许修改 def publish_name(self): return self.publish.name @property # 自定义序列化过程 def author_list(self): temp_author_list = [] for author in self.authors.all(): author_dic = { "name": author.name } try: author_dic['phone'] = author.detail.phone except: author_dic['phone'] = '' temp_author_list.append(author_dic) return temp_author_list @property # 借助序列化类完成序列化过程 def read_author_list(self): from .serializers import AuthorModelSerializer return AuthorModelSerializer(self.authors.all(), many=True).data
serializers.py
# 辅助序列化类 class AuthorDetailModelSerializer(serializers.ModelSerializer): class Meta: model = models.AuthorDetail fields = ['phone'] # 辅助序列化类 class AuthorModelSerializer(serializers.ModelSerializer): detail = AuthorDetailModelSerializer(many=False, read_only=True) class Meta: model = models.Author fields = ['name', 'detail'] # 主序列化类 class BookModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ('name', 'price', 'image', 'publish', 'authors', 'publish_name', 'author_list', 'read_author_list') extra_kwargs = { 'image': { 'read_only': True, }, 'publish': { # 系统原有的外键字段,要留给反序列化过程使用,序列化外键内容,用@property自定义 'write_only': True, }, 'authors': { 'write_only': True, } }
views.py
# 六个必备接口:单查、群查、单增、单删、单整体改(了解)、单局部改 # 四个额外接口:群增、群删、群整体改、群局部改 class BookAPIView(APIView): # 单查群查 def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: obj = models.Book.objects.filter(is_delete=False, pk=pk).first() serializer = serializers.BookModelSerializer(instance=obj) return APIResponse(result=serializer.data) else: queryset = models.Book.objects.filter(is_delete=False).all() serializer = serializers.BookModelSerializer(instance=queryset, many=True) return APIResponse(results=serializer.data) # 单增群增 def post(self, request, *args, **kwargs): # 如何区别单增群增:request.data是{}还是[] if not isinstance(request.data, list): # 单增 serializer = serializers.BookModelSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 如果校验失败,会直接抛异常,返回给前台 obj = serializer.save() # 为什么要将新增的对象重新序列化给前台:序列化与反序列化数据不对等 return APIResponse(result=serializers.BookModelSerializer(obj).data, http_status=201) else: # 群增 serializer = serializers.BookModelSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) # 如果校验失败,会直接抛异常,返回给前台,只要其中一个字典出错就不会走save方法 objs = serializer.save() # 为什么要将新增的对象重新序列化给前台:序列化与反序列化数据不对等 return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data, http_status=201) # 友情注释:群增其实是借助了ListSerializer来的create方法完成的