DRF 序列化
官方文档:https://www.django-rest-framework.org
第一步:
pip清华源安装djangorestframework :
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple djangorestframework
查看 pip 中已经安装的包:pip list | findstr "djangorestframework"
第二步:
配置 settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'APP.apps.AppConfig',
'rest_framework' # 添加该行
]
第三步:
新建文件,编写序列化类
serializers.py
# -*- coding: utf-8 -*- # @File : serializers.py # @Date : 2020-09-14 # @Author : Administrator from rest_framework import serializers class PublisherSerializers(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=32) class AuthorSerializers(serializers.Serializer): id = serializers.IntegerField() Author_name = serializers.CharField(max_length=32) class BookSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=32) CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),) category = serializers.ChoiceField(choices=CHOICES,source='get_category_display') # 显示 CHOICES 中的中文 需设置 source pub_time = serializers.DateField() # 关联外键 publisher = PublisherSerializers() author = AuthorSerializers(many=True) # 告诉 serializers 这是一个 ManyToManyField
重新编写 views 类,注意继承类,要使用 serializers 中的相关数据
views.py
from .models import Book from .serializers import BookSerializer from rest_framework.views import APIView from rest_framework.response import Response class BookView(APIView): # 继承 APIView def get(self,request): # book_obj = Book.objects.first() # ret = BookSerializer(book_obj) book_list = Book.objects.all() ret = BookSerializer(book_list,many=True) # 多条数据时,一定要告诉 BookSerializer 序列化多条数据 return Response(ret.data)
DRF 反序列化
serializers.py
# -*- coding: utf-8 -*- # @File : serializers.py # @Date : 2020-09-14 # @Author : Administrator from rest_framework import serializers from .models import Book class PublisherSerializers(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=32) class AuthorSerializers(serializers.Serializer): id = serializers.IntegerField() Author_name = serializers.CharField(max_length=32) # { # "title": "java入门", # "w_category": 1, # "pub_time": "2020-09-14", # "w_publisher_id": 1, # "w_author_list": [1,2] # } class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),) category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True) # 序列化的时候读 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # 该字段用于反序列化,且只作用于反序列化时 pub_time = serializers.DateField() w_publisher_id = serializers.IntegerField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 w_author_list = serializers.ListField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 # 关联外键 publisher = PublisherSerializers(read_only=True) author = AuthorSerializers(many=True, read_only=True) # 告诉 serializers 这是一个 ManyToManyField 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_id']) book.author.add(*validated_data['w_author_list']) # 多对多进行解包 return book
views.py
from .models import Book, Publisher from .serializers import BookSerializer from rest_framework.views import APIView from rest_framework.response import Response # 第三版 DRF 序列化 class BookView(APIView): # 继承 APIView def get(self, request): # book_obj = Book.objects.first() # ret = BookSerializer(book_obj) book_list = Book.objects.all() ret = BookSerializer(book_list, many=True) # 多条数据时,一定要告诉 BookSerializer 序列化多条数据 return Response(ret.data) # Post 请求,反序列化 def post(self, request): print(request.data) serializers = BookSerializer(data=request.data) if serializers.is_valid(): serializers.save() return Response(serializers.validated_data) else: return Response(serializers.errors)
DRF 获取指定单条数据
urls.py
from django.urls import path,include from .views import BookView,BookEditView urlpatterns = [ path('EditBook/<int:id>',BookEditView.as_view()) ]
view.py
class BookEditView(APIView): def get(self,request,id): book = Book.objects.filter(id=id).first() ret = BookSerializer(book) return Response(ret.data)
DRF 的 PUT 请求部分验证
serializers.py
# -*- coding: utf-8 -*- # @File : serializers.py # @Date : 2020-09-14 # @Author : Administrator from rest_framework import serializers from .models import Book class PublisherSerializers(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=32) class AuthorSerializers(serializers.Serializer): id = serializers.IntegerField() Author_name = serializers.CharField(max_length=32) # { # "title": "java入门", # "w_category": 1, # "pub_time": "2020-09-14", # "w_publisher_id": 1, # "w_author_list": [1,2] # } class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),) category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True) # 序列化的时候读 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # 该字段用于反序列化,且只作用于反序列化时 pub_time = serializers.DateField() w_publisher_id = serializers.IntegerField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 w_author_list = serializers.ListField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 # 关联外键 publisher = PublisherSerializers(read_only=True) author = AuthorSerializers(many=True, read_only=True) # 告诉 serializers 这是一个 ManyToManyField 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_id']) book.author.add(*validated_data['w_author_list']) # 多对多进行解包 return book def update(self, instance, validated_data): instance.title = validated_data.get('title',instance.title) instance.category = validated_data.get('category',instance.category) instance.pub_time = validated_data.get('pub_time',instance.pub_time) instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id) if validated_data.get('w_author_list'): instance.author.set(validated_data['w_author_list']) instance.save() return instance
views.py
class BookEditView(APIView): def get(self,request,id): book_obj = Book.objects.filter(id=id).first() ret = BookSerializer(book_obj) return Response(ret.data) def put(self,request,id): book_obj = Book.objects.filter(id=id).first() ret = BookSerializer(book_obj,data=request.data,partial=True) # partial 是否允许部分更新 if ret.is_valid(): ret.save() return Response(ret.validated_data) else: return Response(ret.errors)
DRF的钩子验证
优先级:局部钩子 > 自定义钩子 > 全局钩子
局部钩子验证
class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),) category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True) # 序列化的时候读 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # 该字段用于反序列化,且只作用于反序列化时 pub_time = serializers.DateField() w_publisher_id = serializers.IntegerField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 w_author_list = serializers.ListField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 # 关联外键 publisher = PublisherSerializers(read_only=True) author = AuthorSerializers(many=True, read_only=True) # 告诉 serializers 这是一个 ManyToManyField 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_id']) book.author.add(*validated_data['w_author_list']) # 多对多进行解包 return book def update(self, instance, validated_data): instance.title = validated_data.get('title',instance.title) instance.category = validated_data.get('category',instance.category) instance.pub_time = validated_data.get('pub_time',instance.pub_time) instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id) if validated_data.get('w_author_list'): instance.author.set(validated_data['w_author_list']) instance.save() return instance # 局部钩子,定义 title 的局部验证 def validate_title(self, vaule): if 'Python' not in vaule: raise serializers.ValidationError('标题必须含有 Python') return vaule
全局钩子验证
class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),) category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True) # 序列化的时候读 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # 该字段用于反序列化,且只作用于反序列化时 pub_time = serializers.DateField() w_publisher_id = serializers.IntegerField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 w_author_list = serializers.ListField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 # 关联外键 publisher = PublisherSerializers(read_only=True) author = AuthorSerializers(many=True, read_only=True) # 告诉 serializers 这是一个 ManyToManyField 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_id']) book.author.add(*validated_data['w_author_list']) # 多对多进行解包 return book def update(self, instance, validated_data): instance.title = validated_data.get('title',instance.title) instance.category = validated_data.get('category',instance.category) instance.pub_time = validated_data.get('pub_time',instance.pub_time) instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id) if validated_data.get('w_author_list'): instance.author.set(validated_data['w_author_list']) instance.save() return instance # 局部钩子,定义 title 的局部验证 def validate_title(self, vaule): if 'Python' not in vaule: raise serializers.ValidationError('标题必须含有 Python') return vaule # 全局钩子 def validate(self, attrs): if attrs['w_publisher_id'] !=2 or attrs['w_category'] != 2: # if 2 not in attrs['w_author_list']: raise serializers.ValidationError('出版社或作者不正确') return attrs
自定义钩子验证
def my_validate(attrs): if "敏感信息" in attrs.lower(): raise serializers.ValidationError('含有了敏感信息') return attrs class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32,validators=[my_validate]) CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),) category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True) # 序列化的时候读 w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) # 该字段用于反序列化,且只作用于反序列化时 pub_time = serializers.DateField() w_publisher_id = serializers.IntegerField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 w_author_list = serializers.ListField(write_only=True) # 该字段用于反序列化,且只作用于反序列化时 # 关联外键 publisher = PublisherSerializers(read_only=True) author = AuthorSerializers(many=True, read_only=True) # 告诉 serializers 这是一个 ManyToManyField
ModelSerializer序列化
serializers.py
from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): category = serializers.CharField(source='get_category_display') publisher = serializers.SerializerMethodField() author = serializers.SerializerMethodField() # 通过自定义 get_publisher 与 get_author 来获取我们想要的指定字段 def get_publisher(self,obj): # obj 是我们序列化的每个 Book 对象 publisher_obj = obj.publisher return {"id":publisher_obj.id,"title":publisher_obj.title} def get_author(self,obj): author_obj = obj.author.all() print(obj.author.all()) return [{'id':author.id,'Author_name':author.Author_name} for author in author_obj] class Meta: model = Book # fields = ['id','title','pub_time'] # 拿到指定信息 fields = '__all__' # 拿到所有信息,但存在关联字段 id 信息,不利于阅读,需要单独处理 # depth = 1 # 获取关联表中的字段,数字代表 深度,但这样回取出所有数据
ModelSerializer反序列化
ModelSerializer 已经默认给我们写了 create 方法
serializers.py
from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): category = serializers.SerializerMethodField(read_only=True) publisher_info = serializers.SerializerMethodField(read_only=True) authors = serializers.SerializerMethodField(read_only=True) def get_category(self, obj): return obj.get_category_display() # 通过自定义 get_publisher 与 get_author 来获取我们想要的指定字段 def get_publisher_info(self, obj): # obj 是我们序列化的每个 Book 对象 publisher_obj = obj.publisher return {"id": publisher_obj.id, "title": publisher_obj.title} def get_authors(self, obj): author_obj = obj.author.all() print(obj.author.all()) return [{'id': author.id, 'Author_name': author.Author_name} for author in author_obj] class Meta: model = Book # fields = ['id','title','pub_time'] # 拿到指定信息 fields = '__all__' # 拿到所有信息,但存在关联字段 id 信息,不利于阅读,需要单独处理 # depth = 1 # 获取关联表中的字段,数字代表 深度,但这样回取出所有数据 # extra_kwargs 添加字段的属性信息 extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True}, "author": {"write_only": True}}