Django REST framework序列化
一.简介
Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API。
官网:https://www.django-rest-framework.org/
中文文档:https://q1mi.github.io/Django-REST-framework-documentation/
二. 安装与配置
1.安装
pip install djangorestframework
2.配置
如果想要获取一个图形化的页面,需要将 rest_framework 注册到项目的INSTALL_APPS中。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'bms.apps.BmsConfig', 'rest_framework', ]
三.DRF序列化
我们写项目想返回的是json数据,使用DRF的序列化工具serializer会非常方便
url:
re_path('books/$',views.BooksView.as_view()), re_path(r'book_pk/(?P<pk>\d+)$', views.BookDetailView.as_view()),
view:
from rest_framework.views import APIView from app01.serializers import BookModelSerializer class BooksView(APIView): # 不带id的查询与新增 """使用Django REST framework 内置的序列化""" def get(self, request): '''以JSON格式返回所有的书籍信息''' # 1.查出所有的书籍信息 queryset = models.Book.objects.all() # 2.使用serializers序列化 ser_obj = BookModelSerializer(queryset, many=True) # 多条数据many=True return Response(ser_obj.data) def post(self, request): '''创建资源''' # 1.获取前端提交的数据 # 1.1 APIView # self.request是谁? 不是Django原来的哪个request self._request才是原来的request # print(request.data) # APIView 包装的数据 # 2.对数据做有效性校验 ser_obj = BookModelSerializer(data=request.data) if ser_obj.is_valid(): ser_obj.save() # 调用的是BookSerializer类中的create方法,需要自己去实现 # 3. 拿到序列化的数据去数据库创建新记录 return Response("ok") else: return Response(ser_obj.errors) class BookDetailView(APIView): '''查询具体的书籍,编辑书籍,删除书籍''' def get(self, request, pk): # 1,根据pk去查询具体的哪儿本书籍对象 book_obj = models.Book.objects.filter(pk=pk).first() if book_obj: # 2. 将书籍对象 序列化成 json格式的数据 ser_obj = BookModelSerializer(book_obj) # 3. 返回响应 return Response(ser_obj.data) else: return Response("无效的书籍id") def put(self, request, pk): """修改具体某一本书""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk).first() if book_obj: # 2. 获取用户 发送过来的数据并且更新对象 # partial=True 允许局部更新,比如只改变部分数据(partial 局部的) ser_obj = BookModelSerializer(instance=book_obj, data=request.data, partial=True) # form组件中也有类似的实现 if ser_obj.is_valid(): # 3. 保存并返回修改后的数据 ser_obj.save() return Response(ser_obj.data) else: return Response(ser_obj.errors) else: return Response("无效的书籍id") def delete(self, request, pk): '''删除具体某一本书''' # 1. 根据pk去查询具体的那本书籍queryset对象;注意不是具体的书籍对象,书籍对象没有delete方法 book_obj = models.Book.objects.filter(pk=pk) if book_obj: # 删除书籍对象 book_obj.delete() return Response("删除成功") else: return Response("无效的书籍id")
serializers.py
class BookSerializers(serializers.Serializer): '''使用Serializer,序列化''' id = serializers.IntegerField(required=False) # required=False 设置为非必须要字段 title = serializers.CharField(max_length=32) pub_date = serializers.DateField() CHOICES = ((1, 'Python'), (2, 'Go'), (3, 'Linux')) # read_only=True 设置为只在查询字段时生效 category = serializers.CharField(source='get_category_display', read_only=True) # read_only=True 设置为只在添加字段,或修改字段时生效 post_category = serializers.IntegerField(write_only=True) publisher = PublisherSerializer(read_only=True) post_publisher = serializers.IntegerField(write_only=True) # many= True 当字段对应多条数据时使用 authors = AuthorSerializer(many=True, read_only=True) post_authors = serializers.ListField(write_only=True) def validate_title(self, attrs): """类似于Form组件的局部勾子函数""" # attrs就是需要检验的这个字段的值 print(attrs) # 红烧牛肉 print('-' * 120) if '红烧牛肉' in attrs: raise serializers.ValidationError('你是魔鬼吗?') else: return attrs def validate_post_publisher(self, attrs): # 判断数据库里面有没有你制定的这个出版社 is_exist = models.Publisher.objects.filter(pk=attrs) if is_exist: return attrs else: raise serializers.ValidationError("你填写的出版社不存在!") # 全局钩子 # def validate(self, attrs): # pass # 校验合格的数据,要想直接 .save()保存数据必须要重写这个方法 def create(self, validated_data): # validated_data经过校验的有效数据 book_obj = models.Book.objects.create( title=validated_data['title'], pub_date=validated_data['pub_date'], category=validated_data['post_category'], publisher_id=validated_data['post_publisher'], # 1 ) book_obj.authors.set(validated_data['post_authors']) return book_obj # 在更新数据的时候支持直接调用save()保存数据 def update(self, instance, validated_data): # print(instance) # 查询出要改变的原数据 # print(validated_data) # 校验合格的更新数据 # 从validated_data中取出数据挨个字段更新 instance.title = validated_data.get('title', instance.title) instance.pub_date = validated_data.get('pub_date', instance.pub_date) instance.category = validated_data.get('post_category', instance.category) instance.publisher_id = validated_data.get('post_publisher', instance.publisher_id) # 永远都不要高估自己! instance.save() # 更新多对多字段的 authors # 先取出当前书籍的所有作者id author_list = instance.authors.all().values_list('id') # [(1,),(2,)] ==> [1, 2] # 然后更新,没变就用原来的数据 instance.authors.set(validated_data.get('post_authors',[i[0] for i in author_list])) # 返回更新后的数据 return instance # 使用modelserializers class BookModelSerializer(serializers.ModelSerializer): '''使用ModelSerializer,序列化''' # SerializerMethodField 会自动去找 get_字段名 的方法执行(设置了SerializerMethodField) category_info = serializers.SerializerMethodField(read_only=True) # 查到关联的对象 publisher_info = serializers.SerializerMethodField(read_only=True) authors_info = serializers.SerializerMethodField(read_only=True) def get_category_info(self, book_obj): # book_obj ==》 当前被序列化的那个书籍对象 return book_obj.get_category_display() def get_publisher_info(self, book_obj): # book_obj.pulisher ==> 得到和我这本书关联的出版社对象 # return { # "id": book_obj.publiser.id, # "name": book_obj.publiser.name # } # ser_obj = PublisherSerializer(book_obj.publisher) # return ser_obj.data return PublisherSerializer(book_obj.publisher).data def get_authors_info(self, book_obj): return AuthorSerializer(book_obj.authors.all(), many=True).data class Meta: model = models.Book fields = "__all__" # depth 1 # 所有有关系的字段都变成 read_only # exclude = [] # 排除某个字段 extra_kwargs = { # 每个字段的一些额外参数也可更改 'publisher': {'write_only': True}, 'authors': {'write_only': True}, 'category': {'write_only': True}, }