Django REST Framework序列化组件
目录:
序列化组件
序列化组件的使用
serializers.py将序列化的部分写在这里
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
pub_time = serializers.DateField()
类视图
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
添加序列化的步骤
- 定义好model和url
- 导入序列化组件:
from rest_framework import serializers
- 定义序列化类,继承serializers.Serializer(建议单独创建一个专用的模块用来存放所有的序列化类):
class BookSerializer(serializers.Serializer)
- 定义需要返回的字段(字段类型可以与model中的类型不一致,参数也可以调整),字段名称必须与model中的一致
- 在GET接口逻辑中,获取QuerySet
- 开始序列化:将QuerySet作业第一个参数传给序列化类,many默认为False,如果返回的数据是一个列表嵌套字典的多个对象集合,需要改为many=True
- 返回:将序列化对象的data属性返回即可
序列化类中的字段名也可以与model中的不一致,但是需要使用source参数来告诉组件原始的字段名
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
pub_time = serializers.DateField()
publisher = serializers.CharField(max_length=32, source="publisher.title")
外键关系序列化
对于一对多可以直接使用publisher.title
的方式
更多的是对外键关系也进行序列化
from rest_framework import serializers
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
pub_time = serializers.DateField()
publisher = PublisherSerializer()
author = AuthorSerializer(many=True)
对于多对多需要添加many=True
反序列化
反序列化获取post等请求的数据进行校验写入数据库的操作
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
def post(self, request):
serializer = BookSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.validated_data)
else:
return Response(serializer.errors)
这里直接使用request.data详细的原理就是
- APIView继承了View,
as_view
返回的是csrf_exempt(view)
跨域请求伪造保护 - 而APIView的view而APIView的
view=super(APIView, cls).as_view(**initkwargs)
,所以这个view还是View的as_view
方法,返回的self.dispatch
self.dispatch
使用的APIView的dispatch
dispatch中
request=initalize_request(request, *arg, **kwargs)
self.request = request
- initalize_request返回的是一个Request(),与之前的request对象不同的是,没有get和post方法,而是有一些其他的方法取代了
- Request中进行了重新封装,
self._request=request
,使用_request
替换了旧的request,query_params=self._request.GET
获取的GET数据,data=self._full_data
获取的POST数据
反序列化对于POST请求需要重写create方法,并且区分序列化的字段
from rest_framework import serializers
from models import Book
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=32)
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
pub_time = serializers.DateField()
publisher = PublisherSerializer(read_only=True)
authors = AuthorSerializer(many=True, read_only=True)
w_category = serializers.IntegerField(write_only=True)
w_publisher = serializers.IntegerField(write_only=True)
w_authors = serializers.ListField(write_only=True)
def create(self, validated_data):
book = Book.objects.create(
title=validated_data["title"],
category=validated_data["w_category"],
pub_time=validated_data["pub_time"],
publisher_id=validated_data["w_publisher"],
)
book.authors.add(*validated_data["w_authors"])
return book
直接使用DRF的前端post数据即可
{
"title": "Django REST Framework(第四版)",
"w_category": 1,
"pub_time": "2019-11-14",
"w_publisher": 1,
"w_authors": [
1, 2
]
}
反序列化修改数据
from rest_framework import serializers
from models import Book
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=32)
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
pub_time = serializers.DateField()
publisher = PublisherSerializer(read_only=True)
authors = AuthorSerializer(many=True, read_only=True)
w_category = serializers.IntegerField(write_only=True)
w_publisher = serializers.IntegerField(write_only=True)
w_authors = serializers.ListField(write_only=True)
def create(self, validated_data):
book = Book.objects.create(
title=validated_data["title"],
category=validated_data["w_category"],
pub_time=validated_data["pub_time"],
publisher_id=validated_data["w_publisher"],
)
book.authors.add(*validated_data["w_authors"])
return book
def update(self, instance, validated_data):
instance.title = validated_data.get("title", instance.title)
instance.category = validated_data.get("w_category", instance.category)
instance.pub_time = validated_data.get("pub_time", instance.pub_time)
instance.publisher_id = validated_data.get("w_publisher", instance.publisher_id)
if validated_data.get("w_authors"):
instance.user.set(validated_data.get("w_authors"))
instance.save()
return instance
view
class BookFilterView(APIView):
def get(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(book_obj)
return Response(ser_obj.data)
def put(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data)
else:
return Response(ser_obj.errors)
url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('drfdemo.urls'))
]
反序列化字段验证
单个字段验证
def validate_title(self, value):
if "python" not in value.lower():
raise serializers.ValidationError("title must include python")
return value
多个字段验证
def validate(self, value):
if "python" not in value["title"].lower() and value["w_category"] == 1:
raise serializers.ValidationError("分类不符合要求")
return value
字段验证器
def my_validate(value):
if "fuck" in value.lower:
raise serializers.ValidationError("包含敏感词汇,请重新提交")
return value
然后使用字段验证器
title = serializers.CharField(max_length=32, validators=[my_validate])
ModelSerializer与Model相对应的序列化器
序列化
直接的创建ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
将get指向的序列化器改为BookModelSerializer
from .serializers import BookSerializer, BookModelSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookModelSerializer(book_list, many=True)
return Response(ret.data)
请求可以看到对应的数据
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"id": 1,
"title": "Django REST Framework(第二版)",
"category": 1,
"pub_time": "2019-11-12",
"publisher": 1,
"authors": [
1,
2
]
},
{
"id": 2,
"title": "Django REST Framework(第三版)",
"category": 1,
"pub_time": "2019-11-13",
"publisher": 1,
"authors": [
1,
2
]
},
{
"id": 3,
"title": "Django REST Framework(第四版)",
"category": 1,
"pub_time": "2019-11-14",
"publisher": 1,
"authors": [
1,
2
]
}
]
外键关系序列化
对于显示ID的问题可以通过depth解决
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
depth = 1
depth代表找嵌套关系的第几层,但是depth会让外键变为只读
覆盖默认字段
class BookSerializer(serializers.ModelSerializer):
category = serializers.CharField(source="get_category_display", read_only=True)
class Meta:
model = Book
fields = "__all__"
depth = 1
使用字段验证器
class BookSerializer(serializers.ModelSerializer):
category = serializers.CharField(source="get_category_display", read_only=True)
class Meta:
model = Book
fields = "__all__"
depth = 1
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,], 'write_only': True}}
反序列化
因为字段中支持序列化和反序列化,更简单的方式就是不使用depth,对get的数据进行处理
class BookModelSerializer(serializers.ModelSerializer):
r_category = serializers.CharField(source="get_category_display", read_only=True)
r_publisher = serializers.SerializerMethodField(read_only=True)
r_authors = serializers.SerializerMethodField(read_only=True)
def get_r_publisher(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.id, "title": publisher_obj.title}
def get_r_authors(self, obj):
authors_queryset = obj.authors.all()
return [{"id": author.id, "name": author.name } for author in authors_queryset]
class Meta:
model = Book
fields = "__all__"
# depth = 1
extra_kwargs = {
"id": {"read_only": True},
"publisher": {"write_only": True},
"authors": {"write_only": True},
}
直接获取结果或者post数据
{
"title": "Django REST Framework(第五版)",
"category": 2,
"pub_time": "2019-11-15",
"publisher": 1,
"authors": [
1
]
}
对于删除
def delete(self, request, id):
query_set = Book.objects.filter(id=id).first()
if query_set:
query_set.delete()
return Response("")
else:
return Response("删除的书籍不存在")