序列化:將Python對象准換成json格式的字符串,反之即為反序列化
DRF的序列化使用過程:
使用drf的序列化組件
-1 新建一個序列化類繼承Serializer
-2 在類中寫要序列化的字段
-在視圖中使用序列化的類
-1 實例化序列化的類產生對象,在產生對象的時候,傳入需要序列化的對象(queryset)
-2 對象.data
-3 return Response(對象.data)
使用示例:
新建Django項目:settings.py文件注冊rest_framework,使用MySQL數據庫創建數據
# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'drf_ser01', 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '123' } } # __init__.py import pymysql pymysql.install_as_MySQLdb()
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(decimal_places=1, max_digits=6) publish = models.ForeignKey(to='Publish') author = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'author')) class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64, null=True) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author')
app01新建MySer.py
# 先創建一個BookSer序列化類 from rest_framework import serializers class BookSer(serializers.Serializer): id = serializers.CharField() title = serializers.CharField() publish = serializers.CharField() author = serializers.CharField()
app01視圖函數views.py中
from django.shortcuts import render,HttpResponse,redirect from app01.MySer import BookSer from rest_framework.response import Response from rest_framework.views import APIView from app01 import models # Create your views here. class Books(APIView): response = {'code': 100, 'msg': '查詢成功'} def get(self, request): books = models.Book.objects.all() books_ser = BookSer(instance=books, many=True) return Response(books_ser.data)
配路由:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^books/', views.Books.as_view()), ]
(通過NaviCat創建圖書數據,用於查詢...)
使用Postman發送get請求,獲取到數據庫中所有圖書信息

可以看出一對多和多對多的外鍵字段顯示的是對象名字,下面進一步使用序列化,讓信息顯示更完善
-source:可以指定字段(name publish.name),可以指定方法 -SerializerMethodField搭配方法使用(get_字段名字)
publish_detail=serializers.SerializerMethodField(read_only=True) def get_publish_detail(self,obj): return {'name':obj.publish.name,'city':obj.publish.city}
更新版本BookSer
from rest_framework import serializers class BookSer(serializers.Serializer): id = serializers.CharField() title = serializers.CharField() publish = serializers.CharField(source='publish.name') author = serializers.SerializerMethodField() def get_author(self, obj): authors = [] for author_obj in obj.author.all(): authors.append({'name': author_obj.name, 'age': author_obj.age}) return authors

補充:
-read_only:反序列化時,不傳 -write_only:序列化時,不顯示
以上是序列化的一種方式
下面看看序列化的另外一種方式:ModelSerializers:指定了表模型
class Meta: model=表模型 #要顯示的字段 fields=('__all__') fields=('id','name') #要排除的字段 exclude=('name') #深度控制 depth=1 -重寫某個字段 在Meta外部,重寫某些字段,方式同Serializers
# 序列化方式二: class BookSer(serializers.ModelSerializer): class Meta: model = models.Book fields = ('__all__')

如果只想取其中幾個字段,可以進行指定:
# 序列化方式二: class BookSer(serializers.ModelSerializer): class Meta: model = models.Book fields = ['id', 'title'] # fields = ('__all__')

剛才看到__all__,序列化所有字段,查詢到的數據里面publish和author都是對應id值,如果需要獲取到對應publish和author的關聯信息,可以在BookSer內,Meta外重新寫字段,方式同serializers
# 序列化方式二: class BookSer(serializers.ModelSerializer): class Meta: model = models.Book # fields = ['id', 'title'] fields = ('__all__') publish = serializers.CharField(source='publish.name') author = serializers.SerializerMethodField() def get_author(self, obj): authors = [] for author_obj in obj.author.all(): authors.append({'name': author_obj.name, 'age': author_obj.age}) return authors

改進:
class AuthorSer(serializers.Serializer): id = serializers.CharField() name = serializers.CharField() age = serializers.CharField() # 序列化方式二改進: class BookSer(serializers.ModelSerializer): class Meta: model = models.Book # fields = ['id', 'title'] fields = ('__all__') publish = serializers.CharField(source='publish.name') author = serializers.SerializerMethodField() def get_author(self, obj): ret = AuthorSer(obj.author.all(), many=True) return ret.data

通過post請求新增數據:
對數據進行新增使用反序列化實現,這里反序列化有2種情況進行新增:
使用繼承了Serializers序列化類的對象,反序列化(需重寫create方法)
from django.db import models # Create your models here. class User(models.Model): name = models.CharField(max_length=32) password = models.CharField(max_length=64) choices = (('1', 'Super_Admin'), ('2', 'General_Admin'), ('3', 'General_User') ) user_type = models.CharField(max_length=6, choices=choices, default='3') class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(decimal_places=1, max_digits=6) publish = models.ForeignKey(to='Publish', null=True) author = models.ManyToManyField(to='Author') class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64, null=True) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField()
class Book(APIView): def post(self, request): response = {'code': 100, 'msg': '新增成功'} # 使用繼承了Serializers序列化類的對象,反序列化 book = BookSer(data=request.data) if book.is_valid(): # 清洗通過的數據,需要在MySer.py中重寫create book.create(book.validated_data) return Response(response)
# MySer.py class BookSer(serializers.Serializer): # read_only 反序列化的時候,該字段不傳 # 這里id可以不傳自增,publish、author不傳,當然需要在models里面把不傳字段設置為null=True # author多對多字段不能設置null=True id = serializers.CharField(read_only=True) title = serializers.CharField() price = serializers.CharField() publish = serializers.CharField(source='publish.id', read_only=True) author = serializers.SerializerMethodField(read_only=True) def get_author(self, obj): ret = AuthorSer(obj.author.all(), many=True) return ret.data # 重寫create方法,才能在使用Serializer發序列化方法進行新增數據 def create(self, validated_data): res = models.Book.objects.create(**validated_data) return res
使用繼承了ModelSerializers序列化類的對象,反序列化
from django.db import models # Create your models here. class User(models.Model): name = models.CharField(max_length=32) password = models.CharField(max_length=64) choices = (('1', 'Super_Admin'), ('2', 'General_Admin'), ('3', 'General_User') ) user_type = models.CharField(max_length=6, choices=choices, default='3') class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(decimal_places=1, max_digits=6) publish = models.ForeignKey(to='Publish', null=True) author = models.ManyToManyField(to='Author') class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64, null=True) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField()
class BookSer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
class Book(APIView): def post(self, request): response = {'code': 100, 'msg': '新增成功'} # 使用繼承了ModelSerializers序列化類的對象,反序列化 book_ser = BookSer(data=request.data) if book_ser.is_valid(): book_ser.save() else: response['error'] = book_ser.errors['name'][0] return Response(response)
使用ModelSerializer反序列化save數據后,多對多關聯的那張表也會自動關聯產生新的數據。
局部校驗和全局校驗
# MySer.py from rest_framework.exceptions import ValidationError class BookSer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" def validate_title(self, value): if value.startswith('sb'): raise ValidationError('不能以sb開頭') return value def validate(self, attrs): title = attrs.get('title') price = attrs.get('price') if title.startswith('禁書') or int(price) <= 15: raise ValidationError('書名或價格不正常') return attrs
總結:
-反序列化的校驗
-validate_字段名(self,value):
-如果校驗失敗,拋出ValidationError(拋出的異常信息需要去bookser.errors中取)
-如果校驗通過直接return value
-validate(self,attrs)
-attrs所有校驗通過的數據,是個字典
-如果校驗失敗,拋出ValidationError
-如果校驗通過直接return attrs
