序列化組件
目錄
# 模型層
from django.db import models
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField()
publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)
class AuthorDatail(models.Model):
nid = models.AutoField(primary_key=True)
telephone = models.BigIntegerField()
birthday = models.DateField()
addr = models.CharField(max_length=64)
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
def __str__(self):
return self.name
def test(self):
return self.email
一、利用for循環來實現序列化(繁瑣)
def get(self, request):
response = {'status': 100, 'data': None}
ll = [{'name': book.name, 'price': book.price} for book in books]
# 返回數據是json格式數據
response['data'] = ll
# safe = True 表示數據可以是列表
return JsonResponse(response, safe=False)
二、利用Django提供的序列化組件(不可控需要的字段)
Django內置的serializers
from django.core import serializers
def get(self,request):
books = models.Book.objects.all()
ret=serializers.serialize('json','queryset對象')
#ret就是序列化之后的字符串了,不需要再序列化了
return HttpResponse(ret)
三、利用drf提供的序列化組件
1、基於Serializer類實現序列化——基本語法
-1 先導入
from rest_framework.serializers import Serializer
from rest_framework import serializers
-2 寫一個類,繼承Serializer
-3 在類內部寫屬性:
name=serializers.CharField()
-4 使用:
先生成對象,需要傳參數 instance:要序列化的對象(可能是queryset,也可能是單個對象)
many:如果是queryset---True,,如果是單個對象--False
-5 序列化的數據:對象.data --->是一個字典
from rest_framework.views import APIView
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
class Book(APIView):
def get(self, request):
# 要序列化的對象(可以是queryset,也可以是單個對象)
# book = models.Books.objects.filter(name='紅樓夢').first()
# ser = BookSerializer(instance=book,many=False)
books = models.Books.objects.all()
ser = BookSerializer(instance=books, many=True)
data = ser.data
return JsonResponse(data, safe=False)
2、基於Serializer類實現序列化——高級語法
(1)非關聯字段或一對多字段
- 可以不用source,直接用 字段名 當變量名,必須為字段名
- 也可以用
source
來指定需要的目標字段 (推薦,盡量讓字段名不要泄露) source
也可以用來指定模型層中的方法- 一對多關聯關系,可以在 source 中用
.
來指定字段,例如取出版社名字,用source='publish.name'
from rest_framework.views import APIView
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 利用source來指定魔表字段,給key取別名
aaa = serializers.CharField(source='name') # 等價於 name = serializers.CharField()
price = serializer.CharField()
publish_name = serializer.CharField(source='publish.name')
# source 也可以用來指定模型層中的方法
t = serializer.CharField(source='publish.test')
class Book(APIView):
def get(self, request):
books = models.Books.objects.all()
ser = BookSerializer(instance=books, many=True)
data = ser.data
return JsonResponse(data, safe=False)
(2)一對多或者多對多字段
- 多對多要用
SerializerMethodField()
,然后定義一個get_變量名
的方法,方法名字必須為 get_變量名 get_變量名
方法要傳參,傳入當前對象,例如在 BookSerializer 中就是book對象- 在
get_變量名
方法中,也可以對數據進行序列化,例如取書的所有作者,就可以對作者序列化然后 return
from rest_framework.views import APIView
from rest_framework import serializers
# 用於對author的數據進行序列化
class AuthorSerializer(serliazer.Serializer):
name = serializer.CharField()
age = serializer.CharField()
class BookSerializer(serializers.Serializer):
# 利用source來給key取別名
aaa = serializers.CharField(source='name') # 等價於 name = serializers.CharField()
price = serializer.CharField()
# book和publish是一對多的關系,也可以用SerializerMethodField
publish = serializer.SerializerMethodField()
def get_publish(self, book):
pub = book.publish.name
return pub
# book和authors是多對多的關系,用SerializerMethodField
au = serializer.SerializerMethodField()
def get_au(self, obj):
aus = obj.authors.all()
ll = []
for obj_au in aus:
ll.append({'au_name':obj_au.name,'au_age':obj_au.age})
return ll
# 也可以在方法中使用序列化類序列化
'''
def get_au(self, book):
# 獲取這本書的所有作者
aus = book.authors.all()
# 可以在方法中對authors的數據進行序列化
au_ser = AuthorSerializer(aus,many=True)
return au_ser.data
'''
class Book(APIView):
def get(self, request):
books = models.Books.objects.all()
ser = BookSerializer(instance=books, many=True)
data = ser.data
return JsonResponse(data, safe=False)
3、基於ModelSerializer類實現序列化
(1)基本語法
from app01.models import Book
# 這樣序列化得到的數據,authors是中都是author_id
class BookSerializer(serializer.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
(2)重寫屬性
from app01.models import Book
# 這樣序列化得到的數據,authors中都是author_id,publish也是publish_id
class BookSerializer(serializer.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
# 重寫屬性authors和publish
puhlish = serializer.CharField(source='publish.name')
authors = serializers.SerializerMethodField()
def get_authors(self,book):
aus = book.authors.all()
# 可以在方法中對authors的數據進行序列化
au_ser = AuthorSerializer(aus,many=True)
return au_ser.data
(3)其他屬性
- fields = ['id','name'] ---------> 指定序列化這兩個字段
- exclude = ['publish','create_time'] ----------> 除了這兩個字段外,其余的序列化
- depth = 2 ----------> 指定深度,即跨表。值為1表示跨一次表;值為2表示跨兩次表
class BookSerializer(serializers.ModelSerializer):
# 必須寫一個內部類,名字叫Meta
class Meta:
model = Book
# fields = '__all__'
# 指定只取這兩個字段
fields = ['nid','name']
# 去掉指定的字段
# exclude=['publish','authors']
# fields,跟exclude不能連用
# 指定深度(官方建議小於10,我給你的建議小於3)
depth = 2
4、HyperlinkedIdentityField(帶鏈接的序列化)-----很少用
# url層
url(r'book/$',views.Book.as_view()),
url(r'publish/(?P<pk>\d+)',views.Publish.as_view(),name='ttt')
# view層
# 定義一個序列化類
class BookSerializer(serializers.Serializers):
name = serializers.CharField()
# view_name:路由的名字;lookup_field:根據表的哪個字段;lookup_url_kwarg:反向解析有名分組的名字。------lookup_field與lookup_url_kwarg相當於是key與value
publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id',lookup_url_kwarg='pk')
# 最后得到的鏈接是: http://127.0.0.1:8000/publish/1
# CBV
class Book(APIView):
def get(self, request):
books = models.Book.objects.all()
# 必須要傳過去request,以便在鏈接中拼接域名
ser = BookSerializer(books, many=True, context={'request':request})
return JsonResponse(ser.data,safe=False)
5、序列化組件之請求數據校驗和保存功能
-
序列化類必須繼承
ModelSerializer
類,只有該類可以指定數據保存修改的目標表模型。倘若一定要繼承Serializer
類,可以通過重寫save方法,來實現保存和修改數據 -
序列化組件校驗和forms組件類似
-
鈎子函數拋異常,異常是 rest_framework.exceptions 下的 ValidationError
-
新增數據:
新增數據,將數據傳入實例化類產生對象,通過is_valid()
校驗,校驗通過,利用序列化對象的save()
方法保存ser=BookSerializer(data=request.data) if ser.is_valid(): ser.save()
-
修改數據:
修改數據一定要在實例化序列化類的時候傳參instance='要修改的對象'
指定要修改的對象ret = models.Book.objects.filter(name=request.data.get('name')).first() ser=BookSerializer(data=request.data, instance=ret') if ser.is_valid(): ser.save()
# 定義一個序列化類
from rest_framework.exceptions import ValidationError
class BookSerializer(serializerss.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
# 校驗和forms組件類似
name = serializers.CharField(max_length=10,required=True,error_message={'max_length':最長不能超過10位,'requered':'必須填'})
# 局部鈎子,value是前端傳過來的數據
def validate_name(self,value):
if value.startswith('aa'):
raise ValidationError('不能以aa開頭')
return value
# 全局鈎子 ,這里的value是上面驗證通過后的所有數據構成的字典
def validate(self,value):
pwd = value.get('pwd')
re_pwd = value.get('re_pwd')
if pwd == re_pwd:
return value
raise ValidationError('兩次密碼不一致')
# CBV
# 1. 新增對象
class Book(APIView):
def post(self, request, *args, **kwargs):
response = {'status': 100, 'msg': None}
data = request.data
ser = BookSerializer(data=data)
if ser.is_valid():
ser.save()
response['msg'] = '創建成功'
else:
response['status'] = 101
response['msg'] = ser.errors
return JsonResponse(response, safe=False)
# CBV
# 2.修改數據
class Book(APIView):
def put(self, request, *args, **kwargs):
response = {'status': 100, 'msg': None}
data = request.data
ser = BookSerializer(data=data,instance=)
if ser.is_valid():
ser.save()
response['msg'] = '創建成功'
else:
response['status'] = 101
response['msg'] = ser.errors
return JsonResponse(response, safe=False)