Django框架深入了解_02(DRF之序列化、反序列化)


序列化:將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()
MySQL數據庫連接
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')
models

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM