drf之ModelSerializer

简介

与表做强关联,之后不需要再写create与update函数了,但当前端传入的数据与表模型中的字段不对应时,需要重写create/update方法,如下:
前端传来的数据为:{'name':'jack','age':18,'gender':'man','addr':'boat'}
而后端的表为:A表有name和age字段,B表有gender与addr字段。
这时序列化类与A表做了强关联,他有A表字段,但没有B表的字段,这时就需要重写create/update方法,使数据写入到两个表

官网:https://www.django-rest-framework.org/api-guide/serializers/

语法

有多种写法,局部钩子与全局钩子是一样的

class 类名(serializers.ModelSerializer)
    # 固定写法,在类中再定义一个Meta
    class Meta:
        # 与表做强关联,左边的字段必须是model
        model = models.Book
        # 查询所有字段,但在显示外键时,会显示外键的字段id,并不是名。
        fields = '__all__'
        # 也可以使用fields指定字段,列表中进行注册
        fields = ['字段名1', '字段名2', ...]
        # 只读字段
        read_only_fields = ['字段名1', '字段名2']
        # 只写字段write_only_fields(此方法在drf3中已弃用)
        # write_only_fields = ['字段名1', '字段名2']
        # 对字段定制限制,方法一:在Meta中定制
        extra_kwargs = {'字段名': {'max_length': 8, 'error_messages': {'max_length': '不能超过8个字符'}},
                        '字段名': {'read_only': True}
                        '字段名': {'write_only': True}}

    # 方法二:在Meta类外定义,且需要在Meta中的fields中进行注册,如:
    name = serializers.CharField(max_length=8, error_messages={'max_length': '不能超过8个字符'})
    price = serializers.CharField(max_length=8)
    publish = serializers.SerializerMethodField()
    def get_publish(self, obj):
        # 这里的obj其实就相当于Book.publish.name中的Book
        return {'name': obj.publish.name, 'phone': obj.publish.addr}
    # 多对多关系的字定义
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        author_list = []
        for author in obj.authors.all():
            author_list.append({'name': author.name, 'phone': author.phone})
        return author_list
  • 如下图,使用fields='__all__'后,前端获取到的是字段id号

示例

  • models.py
models.py
```python
from django.db import models


# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    # 图书与出版社外键字段,一对多
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    # 图书与作者外键字段,多对多
    authors = models.ManyToManyField(to='Author')

    @property
    def publish_detail(self):
        return {'name': self.publish.name, 'addr': self.publish.addr}

    @property
    def author_detail(self):
        author_list = []
        for author in self.authors.all():
            author_list.append({'name': author.name, 'phone': author.phone})
        return author_list


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=11)
  • views.py
from app01 import models
from app01.serializer.serializer import BookModelSerializer
from rest_framework.views import APIView
from rest_framework.response import Response


class BookView(APIView):
    # 查询所有
    def get(self, request):
        book_obj = models.Book.objects.all()
        book_ser = BookModelSerializer(instance=book_obj, many=True)
        return Response(book_ser.data)

    # 新增一条数据
    def post(self, request):
        book_ser = BookModelSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response({'code': 200, 'msg': '新增成功', 'result': book_ser.data})
        else:
            return Response({'code': 201, 'msg': book_ser.errors})


class BookDetailView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        book_ser = BookModelSerializer(instance=book_obj)
        return Response(book_ser.data)

    def put(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        book_ser = BookModelSerializer(data=request.data, instance=book_obj)
        if book_ser.is_valid():
            book_ser.save()
            return Response({'code': '200', 'msg': '修改成功', 'result': book_ser.data})
        else:
            return Response({'code': '201', 'msg': book_ser.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).delete()
        return Response({''})

使用Meta进行定义

  • serializer.py
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ['name', 'price', 'publish_detail', 'author_detail', 'publish', 'authors']
        extra_kwargs = {'name': {'max_length': 8, 'error_messages': {'max_length': '不能超过8个字符'}},
                        'price': {'max_length': 8},
                        'publish_detail': {'read_only': True},  # 此字段是在models.py中定义的
                        'author_detail': {'read_only': True},   # 此字段是在models.py中定义的
                        'publish': {'write_only': True},
                        'authors': {'write_only': True}}

在Meta类外进行定义

  • serializer.py
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ['name', 'price', 'publish', 'authors', 'publish_detail', 'author_detail']
        read_only_fields = ['publish_detail', 'author_detail']   # 此字段是在models.py中定义的
        write_only_fields = ['publish', 'authors']
    # 注意下面两个字段是写在Meta外的
    name = serializers.CharField(max_length=8, error_messages={'max_length': '不能超过8个字符'})
    price = serializers.CharField(max_length=8)

对比使用Serializer定义的序列化类

class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()

    # 定义read_only
    publish_detail = serializers.DictField(read_only=True)
    author_detail = serializers.ListField(read_only=True)

    # 定义write_only
    publish = serializers.CharField(write_only=True)
    authors = serializers.ListField(write_only=True)


    # 以下的代码全部都被节省了
    def create(self, validated_data):
        data = validated_data
        book = models.Book.objects.create(name=data.get('name'),
                                          price=data.get('price'),
                                          publish_id=data.get('publish'))
        # 多对多的新增
        book.authors.add(*data.get('authors'))
        return book

    def update(self, instance, validated_data):
        # instance是要修改的对象
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish_id = validated_data.get('publish')
        authors = validated_data.get('authors')
        instance.authors.clear()  # 先清空关联关系
        instance.authors.add(*authors)
        # 保存instance
        instance.save()
        return instance
posted @   树苗叶子  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示