ModelSerializer插拔式序列化

建数据库

>: mysql -uroot -p密码
>: create database day83 charset=utf8;

表分析

书表Book:name price 				  create_time is_delete 			authors publish
出版社表Publish:name address phone   create_time is_delete
作者表Author:name icon telephone 	  create_time is_delete
作者详情表AuthorDetail:age sex info   create_time is_delete 			  author

表关系

Book 与 Publish 一对多
Book 与 Autho 多对多
Author 与 AuthorDetail 一对一

model类

"""
外键处理:

反向查询名字:related_name
表关系:db_constraint + on_delete  
    db_constraint=False => 断开表关系
    on_delete=models.CASCADE  级联
    on_delete=models.SET_NULL, null=True  设置为空
    on_delete=models.SET_DEFAULT, default=0  设置成默认值0
    on_delete=models.DO_NOTHING  不处理
注:多对多关系不需要明确on_delete
"""
from django.conf import settings
class BaseModel(models.Model):
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    is_delete = models.BooleanField(verbose_name='是否删除', default=False)
    class Meta:
        # 有该属性的Model类不会完成数据库迁移产生一张表 - 基表
        abstract = True


class Publish(BaseModel):
    name = models.CharField(verbose_name='出版社名', max_length=32)
    address = models.CharField(verbose_name='地址', max_length=64)
    phone = models.CharField(verbose_name='电话', max_length=32)
    class Meta:
        db_table = 'o_Publish'
        verbose_name = '出版社'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.name


class Author(BaseModel):
    name = models.CharField(verbose_name='作者名', max_length=32)
    icon = models.FileField(upload_to='icon', default='icon/icon.jpg')
    telephone = models.CharField(verbose_name='电话', max_length=32)
    class Meta:
        db_table = 'o_Author'
        verbose_name = '作者'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.name

class AuthorDetail(BaseModel):
    CHOICE_SEX = (
        (0, '男'),
        (1, '女')
    )
    age = models.IntegerField(verbose_name='年龄')
    sex = models.IntegerField(verbose_name='性别', choices=CHOICE_SEX, default=0)
    info = models.TextField(verbose_name='个人详情')
    author = models.OneToOneField(verbose_name='作者', to='Author', db_constraint=False, on_delete=models.CASCADE, related_name='detail')
    class Meta:
        db_table = 'o_AuthorDetail'
        verbose_name = '作者详情'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.author.name + '的详情'


class Book(BaseModel):
    name = models.CharField(verbose_name='书名', max_length=32)
    price = models.DecimalField(verbose_name='价格', max_digits=5, decimal_places=2, default=66.66)
    authors = models.ManyToManyField(verbose_name='作者们', to='Author', db_constraint=False, related_name='books')
    publish = models.ForeignKey(verbose_name='出版社', to='Publish', db_constraint=False, on_delete=models.CASCADE,
                                related_name='books')

    class Meta:
        db_table = 'o_Book'
        verbose_name = '书籍'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

    # 插拔字段 - 默认为read_only(不需要考虑反序列化),且不能修改
    @property
    def publish_name(self):
        return self.publish.name

    @property
    def publish_detail(self):
        from . import serializers
        return serializers.PublishesModelSerializer(self.publish).data

    @property
    def author_list(self):
        author_arr = []
        for author in self.authors.all():
            author_arr.append(author.name)
        return author_arr

    @property
    def author_detail_list(self):
        author_detail_arr = []
        for author in self.authors.all():
            author_dic = {}
            author_dic['name'] = author.name
            author_dic['age'] = author.detail.age
            author_dic['telephone'] = author.telephone
            # author.icon是对象类型,不能序列化
            author_dic['icon'] = settings.MEDIA_URL + str(author.icon)
            author_detail_arr.append(author_dic)
        return author_detail_arr

配置media

# settings.py 配置文件
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# urls.py 中路由文件
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from django.conf import settings
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
]

Serializer序列化类配置

from rest_framework import serializers
from . import models


class TempSerializer(serializers.Serializer):
    # 序列化()可以为空
    k1 = serializers.CharField()
    # 反序列化通常有校验的条件
    k2 = serializers.CharField(write_only=True, max_length=32, min_length=3, error_messages={
        'max_length': '超长',
        'min_length': '超短',
    })
    k3 = serializers.CharField()



class AuthorsModelSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('name', 'icon', 'telephone')
        model = models.Author


class PublishesModelSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('name', 'address', 'phone')
        model = models.Publish
        extra_kwargs = {}


class BooksModelSerializer(serializers.ModelSerializer):
    # 自定义字段 不建议 书写在Serializer类中,迁移到Model类中
    # 在ModelSerializer类的class Meta中 fields 字段值不能为__all__,因为publish_name字段必须参与序列化
    # publish_name = serializers.SerializerMethodField()
    # def get_publish_name(self, book_obj):
    #     return book_obj.publish.name

    # 只可序列化,导致反序列化崩溃 用Model插拔式自定义字段完成连表深度查询
    # publish = PublishesModelSerializer()

    class Meta:
        # 关联的Model类
        model = models.Book
        # 提供该表所有与数据库表对应的字段,不能和exclude同时出现
        # fields = '__all__'
        # 刨除该表的某些字段 - 不常用
        # exclude = ('id', 'create_time', 'is_delete')
        # 外键自动深度查询 - 不常用
        # depth = 1
        # 自定义提供该表的哪些字段 - 重点:可以插拔Model类中自定义字段 - 插拔式
        fields = ('name', 'price', 'publish', 'authors', 'publish_name', 'publish_detail', 'author_list', 'author_detail_list')

        # 1)可以区分 序列化(read_only) 与 反序列化(write_only) 字段
        # 2)提供系统默认校验信息即校验失败信息
        extra_kwargs = {
            'publish': {
                'write_only': True
            },
            'authors': {
                'write_only': True
            },
            'publish_name': {
                'read_only': True,
            },
            'price': {
                # 数据库字段设置了默认值,也需要 反序列化 时必须提供该字段
                'required': True,
                'error_messages': {
                    'required': '价格不能为空',
                }
            },
            'name': {
                'min_length': 3,
                'error_messages': {
                    'min_length': '太短',
                }
            },
        }

    # ModelSerializer重写了 update 和 create,如果没有特殊业务要求,可以不需要再重写
    def create(self, validated_data):
        authors = validated_data.pop('authors')
        book_obj = models.Book.objects.create(**validated_data)
        # 关系表的新增
        # 关系表的相关操作 增add 删remove 改set 清空clear
        book_obj.authors.add(*authors)
        return book_obj

    # def update(self, instance, validated_data):
    #     return instance

Views视图层配置

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import models, serializers
from utils.response import APIResponse
class BooksAPIView(APIView):
    # 获取所有
    def get(self, request, *args, **kwargs):
        books_query = models.Book.objects.all()
        books_data = serializers.BooksModelSerializer(books_query, many=True).data

        return APIResponse(0, 'ok', books_data)

    # 新增一个
    def post(self, request, *args, **kwargs):
        request_data = request.data
        book_ser = serializers.BooksModelSerializer(data=request_data)

        if book_ser.is_valid():
            book_obj = book_ser.save()
            return Response({
                'status': 1,
                'msg': 'failed',
                'results': serializers.BooksModelSerializer(book_obj).data
            })
        else:
            return Response({
                'status': 1,
                'msg': 'failed',
                'results': book_ser.errors
            })

    # 修改一个
    def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk', 1)
        book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
        book_ser = serializers.BooksModelSerializer(instance=book_obj, data=request.data)
        if book_ser.is_valid():
            book_obj = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.BooksModelSerializer(book_obj).data
            })
        else:
            return Response({
                'status': 1,
                'msg': 'failed',
                'results': book_ser.errors
            })

    # 删除一个 /books/1/ | 删除多个 /books/  数据[1, 2]
    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]
        else:
            pks = request.data
        delete_rows = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
        if delete_rows != 0:
            return APIResponse(0, 'ok')
        return APIResponse(1, '删除失败')



class AuthorsAPIView(APIView):
    # 获取所有
    def get(self, request, *args, **kwargs):
        authors_query = models.Author.objects.all()
        authors_data = serializers.AuthorsModelSerializer(authors_query, many=True).data

        return Response({
            'status': 0,
            'msg': 'ok',
            'results': authors_data
        })


class PublishesAPIView(APIView):
    # 获取所有
    def get(self, request, *args, **kwargs):
        publishes_query = models.Publish.objects.all()
        publishes_data = serializers.PublishesModelSerializer(publishes_query, many=True).data

        # return Response({
        #     'status': 0,
        #     'msg': 'ok',
        #     'results': publishes_data
        # })

        from utils.response import APIResponse
        return APIResponse(0, 'ok', result=123,
                           headers={
            'Token': 'as12df.88og5z.qw12cv'
        }, status=status.HTTP_200_OK)

""" Response类
    data:要返回给前台的数据
    status:响应的网络状态码
    template_name:drf也可以渲染页面
    headers:响应头
    exception:异常信息
    content_type:响应的数据类型,接口默认application/json
    
def __init__(self, data=None, status=None,
             template_name=None, headers=None,
             exception=False, content_type=None):
             
    return Response({
            'status': 0,
            'msg': 'ok',
            'results': publishes_data
        }, headers={
            'Token': 'as12df.88og5z.qw12cv'
        }, status=status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED)
        

from utils.response import APIResponse
        return APIResponse(0, 'ok', result=123,
                           headers={
            'Token': 'as12df.88og5z.qw12cv'
        }, status=status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED)
"""
posted @ 2019-08-18 20:17  Huanghongzheng  阅读(338)  评论(0编辑  收藏  举报