1. 程式人生 > >Django框架(十九)—— 序列化元件(serializer)

Django框架(十九)—— 序列化元件(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 = serializer.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