pip install...
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": []
}
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
CHOICES = ((1, 'Python'), (2, 'Linux'), (3, 'GoLang'))
category = models.IntegerField(choices=CHOICES)
pub_time = models.DateField()
publisher = models.ForeignKey(to='Publisher', on_delete=models.DO_NOTHING, null=True) # 书籍外键指向出版社
authors = models.ManyToManyField(to='Author') # 书籍多对多指向作者
class Publisher(models.Model):
publisher_name = models.CharField(max_length=32)
class Author(models.Model):
author_name = models.CharField(max_length=32)
2.2.1 from rest_framework import serializers
2.2.2 继承 serializers.Serializer
2.2.3 序列化类的字段名和models的字段名必须一样,只是models.xxx变成了serializers.xxx,
可以定义 error_messages 或者 required,跟form表单类似
2.2.4 注意models里面的CHOICE字段这里变成CharField,指定source参数,参数跟随的是ORM的操作,
这里主要注意 "get_CHOICE字段名_display" 方法的使用
2.2.5 主外键关系:主表字段名 = 外键类(),多对多关系时注意指定many=True参数
2.2.6 -- required=False 只序列化不走校验 -- read_only=True 只序列化用 -- write_only=True 只反序列化用
2.2.7 可以自定义字段名,自定义字段一般只用于反序列化
2.2.8 创建数据要重写 create() 方法,更新数据要重写 update() 方法,函数里面是ORM的操作
2.2.9 -- 可自定义校验函数 my_validate(),权重最高,第一个校验,校验函数可以是多个,
在序列化字段里面注意指定 validators=[my_validate, ],将校验函数添加进参数列表
-- 对单个序列化字段的校验函数,权重第二,第二个校验,validate_字段名()
-- 对反序列化的字段进行联合校验,权重第三,第三个校验 ,validate()
from rest_framework import serializers
from DjangoDemo import models
from rest_framework.exceptions import ValidationError
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
publisher_name = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
# 定义自己的字段反序列化校验器
# 校验顺序第一
def my_validate(value):
if 'python' in value.lower():
return raise ValidationError({'title': '标题含有敏感字'})
return value
# Book 主类
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32, validators=[my_validate, ]) # 指定校验器
"不再是InterField,CHOICE 改成 CharFiled,指定 source 跟随 ORM 操作"
"get_字段_display,直接获得 choice 后面的值"
category = serializers.CharField(
source='get_category_display',
read_only=True,
error_messages={'required': '分类不能为空'}
)
"定义新的反序列化字段为了跟 category 区分开来,write_only"
post_category_id = serializers.IntegerField(write_only=True)
pub_time = serializers.DateField(
error_messages={'required': '出版时间不能为空', 'invalid': '时间格式错误'}
)
"外键"
"对该出版社和作者只行进get只读的序列化"
publisher = PublisherSerializer(read_only=True)
"外键,书籍和作者之间多对多"
authors = AuthorSerializer(many=True, read_only=True)
"定义id只写入,反序列化字段必须和传输字段一样!"
publisher_id = serializers.IntegerField(write_only=True)
author_list = serializers.ListField(write_only=True)
############################################################################
# 创建数据需要重新写create方法
def create(self, validated_data):
"validated_data就是校验之后的数据"
"准备对校验过的数据进行ORM的操作"
created_book_obj = models.Book.objects.create(
title=validated_data['title'],
pub_time=validated_data['pub_time'],
category=validated_data['post_category_id'],
publisher_id=validated_data['publisher_id']
)
created_book_obj.authors.add(*validated_data['author_list'])
"return 完才算真正创建完这个对象"
return created_book_obj
# 更新数据需要重写update方法
def update(self, instance, validated_data):
"validated_data就是校验之后的数据"
instance.title = validated_data.get('title', instance.title)
instance.pub_time = validated_data.get('pub_time', instance.pub_time)
instance.category = validated_data.get('post_category_id', instance.category)
instance.publisher_id = validated_data.get('publisher_id', instance.publisher_id)
if validated_data.get('author_list'):
instance.authors.set(validated_data.get('author_list'))
instance.save()
return instance
#############################################################################
# 固定用法,validate_XXX,代表对该字段进行校验
# 校验顺序第二
@staticmethod
def validate_title(value):
if 'python' in value.lower():
raise ValidationError({'title': '包含敏感关键字'})
return value
# 使用该方法对反序列化的字段进行联合校验
# attrs代表的是传过来的所有的字段
# 校验顺序第三
def validate(self, attrs):
author_list = attrs.get('author_list')
if 校验 author_list 失败:
raise ValidationError({'authors': '作者不存在'})
return attrs
3.1 继承 serializers.ModelSerializer
3.2 自定义字段 + serializers.SerializerMethodField() 方法字段的使用,一般自定义参数展示指定 read_only=True
3.3 get_XXX 自定义字段名称,该函数的返回值会返回给该自定义字段
3.4 obj 就是序列化的每一个表类对象
3.5 注意 class Meta 里面的参数设置 model ,fields,exclude,extra_kwargs
3.6 这里同样可以写单个字段的校验和联合校验,validate_字段名(),校验单个字段,validate(),对反序列化的字段
进行联合校验,同样单个字段校验权重最高,联合校验权重最低
3.7 批量更新的时候在 class Meta 中定义list_serializer_class
class BookSerializer(serializers.ModelSerializer):
# 指定的方法字段,可以对字段进行自定义重写
category_info = serializers.SerializerMethodField(read_only=True)
publisher_info = serializers.SerializerMethodField(read_only=True)
authors_info = serializers.SerializerMethodField(read_only=True)
# obj 就是序列化的每一个Book对象
# get_XXX 自定义字段名称,该函数的返回值会返回给该自定义字段
@staticmethod
def get_category_info(obj):
return obj.get_category_display()
@staticmethod
def get_publisher_info(obj):
publisher_obj = obj.publisher
return {'id': publisher_obj.id, 'publisher_name': publisher_obj.publisher_name}
@staticmethod
def get_authors_info(obj):
# 拿到所有的作者对象,列表推导式
authors_queryset = obj.authors.all()
return [{'id': author.id, 'author\'s name': author.name} for author in authors_queryset]
# 校验 title 字段
@staticmethod
def validate_title(value):
if 'python' in value.lower():
raise ValidationError({'title': '包含敏感关键字'})
return value
# 使用该方法对反序列化的字段进行联合校验
def validate(self, attrs):
author_list = attrs.get('author_list')
if 校验 author_list 失败:
raise ValidationError({'authors': '作者不存在'})
return attrs
class Meta:
# 用于更新多条数据
class MultiUpdateSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
# 这里的instance代表的是对象模型列表, validated_data 是数据列表
# child 代表每一个更新对象
# child 调用的 update 是每一个 BookSerializer 的对象
return [self.child.update(instance[i], validated_data[i]) for i in range(len(validated_data))]
# 当存在多条更新的时候
list_serializer_class = MultiUpdateSerializer
model = models.Book
# 这里代表的是默认拿到这张表的所有的字段
fields = '__all__'
# exclude=['id']
# 将该字段设置为只写,将不会给前端传递该字段的参数
extra_kwargs = {
'title': {
'write_only': True,
'min_length': 2,
'error_messages': {
'min_length': '标题最小长度不能低于2',
}
},
'publisher': {
'write_only': True,
'required': True,
'error_messages': {
'required': '出版社id不能为空',
'incorrect_type': '错误的出版社格式' # 外键类型
'does_not_exist': '不存在的出版社'
}
},
'pub_time': {'error_messages': {
'invalid': '参数类型不合法'
}},
'authors': {
'write_only': True,
'error_messages': {
'required': '作者字段不能为空',
'not_a_list': '不合法的作者序列', # 列表类型
'does_not_exist': '不存在的作者',
}
},
'category': {
'write_only': True,
},
}
4.视图中
4.0 from rest_framework.views import APIView, Response
4.1 from SerDemo.serializers import BookSerializer,导入自己写的序列化器
4.2 这里的类继承的 APIView,不是 View
4.3 这里返回的是 Response,不是HTTPResponse
4.4 知道接口传递过来的参数在 request.data 里面
4.5 get 请求直接传 queryset,post 请求是 data=XXX
4.6 无论是 queryset 还是单个 obj,或者是 接口的 request.data,都要入参给 XxxSerializers
4.7 在传 queryset 的时候,注意指定 many=True 参数
4.8 注意 save
4.9 成功返回 ser_obj.data
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer
from . import models
from rest_framework.request import Request
class TestView(APIView):
@classmethod
def get(cls, request: Request):
"""查询"""
book_queryset = models.Book.objects.all()
ser_obj = BookSerializer(book_queryset, many=True)
return Response(ser_obj.data)
@classmethod
def post(cls, request: Request):
"""新增"""
book_obj = request.data
ser_obj = BookSerializer(data=book_obj, many=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
return Response(ser_obj.errors)
@classmethod
def put(cls, request: Request):
"""修改"""
"""注释部分是单条修改"""
# book_obj = models.Book.objects.filter(id=request.data.get('id')).first()
# ser_obj = BookSerializer(instance=book_obj, data=request.data)
# print('是否校验通过-->', ser_obj.is_valid())
# if ser_obj.is_valid():
# ser_obj.save()
# return Response(ser_obj.data)
# return Response(ser_obj.errors)
update_list = request.data
book_model_list = [
models.Book.objects.filter(id=item['id']).first() for item in update_list
]
ser_obj = BookSerializer(instance=book_model_list, data=request.data, many=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
return Response(ser_obj.errors)
@classmethod
def delete(cls, request: Request):
"""删除"""
id_list = request.data.get('id_list')
delete_queryset = models.Book.objects.filter(id__in=id_list)
if delete_queryset.count() != len(id_list):
return Response('不存在的id')
delete_queryset.delete()
return Response('操作成功')
# 数据结构 post 或者 delete,post 不用传 id
[
{
"id":35,
"title": "日bbbb",
"category": 1,
"pub_time": "2020-02-29",
"publisher": 2,
"authors": [1,2]
}
]
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。