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
分类:
python相关 / drf
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通