Django框架(十九)—— drf:序列化组件(serializer)

序列化组件

# 模型层
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)
博客内容仅供参考,部分参考他人优秀博文,仅供学习使用

序列化组件

# 模型层
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)

猜你喜欢

转载自www.cnblogs.com/zhuzhiwei-2019/p/10779196.html