drf序列化及反序列化


假如把drf看做一個漢堡包,我們之前講的模塊屬於漢堡包前面的蓋蓋(請求模塊、渲染模塊)和底底(異常模塊、解析模塊、響應模塊),但是真正中間的夾心沒有講,那么今天我就和大家來看一下漢堡包的夾心(序列化及反序列化)到底是什么東西。

drf序列化(Serializer)

什么是drf序列化?序列化就是將Model對象序列化成字符串用戶傳輸

序列化使用

數據准備

models.py

class User(models.Model):
    SEX_CHOICES = [
        [0, '男'],
        [1, '女'],
    ]
    name = models.CharField(max_length=64)
    pwd = models.CharField(max_length=32)
    phone = models.CharField(max_length=11, null=True, default=None)
    sex = models.IntegerField(choices=SEX_CHOICES, default=0)
    icon = models.ImageField(upload_to='icon', default='icon/default.jpg')

    class Meta:
        # 自定義創建的表名
        db_table = 'user'
        # admin界面中顯示的表名與表名復數形式
        verbose_name = '用戶'  #復數形式
        verbose_name_plural = verbose_name   #非復數形式

    def __str__(self):
        return self.name

配置層: settings.py

# 注冊rest_framework
INSTALLED_APPS = [
    # ...
    'rest_framework',
]

# 配置數據庫
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db',
        'USER': 'root',
        'PASSWORD': 'root'
    }
}

# media資源
MEDIA_URL = '/media/'  # 后期高級序列化類與視圖類,會使用該配置
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')  # media資源路徑

# 國際化配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
  • 主路由:
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from django.conf import settings
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 路由分發
    url(r'^api/', include('api.urls')),
    # 暴露靜態文件
    url('^media/(?P<path>.*)', serve, {'document_root':settings.MEDIA_ROOT})
]
  • 子路由:
urlpatterns = [
    url(r'^users/$', views.User.as_view()),
    url(r'^users/(?P<pk>.*)/$', views.User.as_view()),
]

序列化使用

注意:

- 序列化提供給前台的字段個數由后台決定,可以少提供,
- 但是提供的數據庫對應的字段,名字一定要與數據庫字段相同
- 設置方法字段,字段名可以隨意,字段值有 get_字段名 提供,來完成一些需要處理在返回的數據
- 序列化組件 - 為每一個model類通過一套序列化工具類
- 序列化組件的工作方式與django froms組件非常相似
  • 序列化層:api/serializers.py
"""
1)設置需要返回給前台 那些model類有對應的 字段,不需要返回的就不用設置了
2)設置方法字段,字段名可以隨意,字段值有 get_字段名 提供,來完成一些需要處理在返回的數據
"""
# 序列化組件 - 為每一個model類通過一套序列化工具類
# 序列化組件的工作方式與django froms組件非常相似
from rest_framework import serializers, exceptions
from django.conf import settings

from . import models

class UserSerializer(serializers.Serializer):
    name = serializers.CharField()
    phone = serializers.CharField()
    # 序列化提供給前台的字段個數由后台決定,可以少提供,
    # 但是提供的數據庫對應的字段,名字一定要與數據庫字段相同
    # sex = serializers.IntegerField()
    # icon = serializers.ImageField()

    # 自定義序列化屬性
    # 屬性名隨意,值由固定的命名規范方法提供:
    #       get_屬性名(self, 參與序列化的model對象)
    #       返回值就是自定義序列化屬性的值
    gender = serializers.SerializerMethodField()
    def get_gender(self, obj):
        # choice類型的解釋型值 get_字段_display() 來訪問
        return obj.get_sex_display()


    icon = serializers.SerializerMethodField()
    def get_icon(self, obj):
        # settings.MEDIA_URL: 自己配置的 /media/,給后面高級序列化與視圖類准備的
        # obj.icon不能直接作為數據返回,因為內容雖然是字符串,但是類型是ImageFieldFile類型
        return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.icon))
  • 視圖層
"""
1)從數據庫中將要序列化給前台的model對象,或是對個model對象查詢出來
	user_obj = models.User.objects.get(pk=pk) 或者
	user_obj_list = models.User.objects.all()
2)將對象交給序列化處理,產生序列化對象,如果序列化的是多個數據,要設置many=True
	user_ser = serializers.UserSerializer(user_obj) 或者
	user_ser = serializers.UserSerializer(user_obj_list, many=True)
	#many會遍歷user_obj_list,觸發是一個具體對象
3)序列化 對象.data 就是可以返回給前台的序列化數據
	return Response({
        'status': 0,
        'msg': 0,
        'results': user_ser.data
    })
"""
class User(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            try:
                # 用戶對象不能直接作為數據返回給前台
                user_obj = models.User.objects.get(pk=pk)
                # 序列化一下用戶對象
                user_ser = serializers.UserSerializer(user_obj)
                # print(user_ser, type(user_ser))
                return Response({
                    'status': 0,
                    'msg': 0,
                    'results': user_ser.data
                    #看源碼:data=empty 是參與反序列化的數據
                })
            except:
                return Response({
                    'status': 2,
                    'msg': '用戶不存在',
                })
        else:
            # 用戶對象列表(queryset)不能直接作為數據返回給前台
            user_obj_list = models.User.objects.all()
            # 序列化一下用戶對象
            user_ser_data = serializers.UserSerializer(user_obj_list, many=True).data
            return Response({
                'status': 0,
                'msg': 0,
                'results': user_ser_data
            })

反序列化使用

什么是drf的反序列化?emmm,丫就是將字符串反序列化成Model對象用於使用

  • 反序列層:api/serializers.py
"""
1)設置必填與選填序列化字段,設置校驗規則
2)為需要額外校驗的字段提供局部鈎子函數,如果該字段不入庫,且不參與全局鈎子校驗,可以將值取出校驗
3)為有聯合關系的字段們提供全局鈎子函數,如果某些字段不入庫,可以將值取出校驗
4)重寫create方法,完成校驗通過的數據入庫工作,得到新增的對象
"""
from rest_framework import serializers, exceptions
from django.conf import settings
from . import models

class UserDeserializer(serializers.Serializer):
    # 1) 哪些字段必須反序列化   :入庫的字段都需要反序列化
    # 2) 字段都有哪些安全校驗  :比如字段長度啊,什么的
    # 3) 哪些字段需要額外提供校驗  :name或者password
    # 4) 哪些字段間存在聯合校驗  :需要用到全局鈎子的字段哈哈哈
    # 注:反序列化字段都是用來入庫的,不會出現自定義方法屬性,會出現可以設置校驗規則的自定義屬性(re_pwd)
    name = serializers.CharField(
        max_length=64,
        min_length=3,
        error_messages={
            'max_length': '太長',
            'min_length': '太短'
        }
    )
    pwd = serializers.CharField()
    phone = serializers.CharField(required=False)
    sex = serializers.IntegerField(required=False)

    # 自定義有校驗規則的反序列化字段
    re_pwd = serializers.CharField(required=True)

    # 小結:
    # name,pwd,re_pwd為必填字段
    # phone,sex為選填字段
    # 五個字段都必須提供完成的校驗規則


    # 局部鈎子:validate_要校驗的字段名(self, 當前要校驗字段的值)
    # 校驗規則:校驗通過返回原值,校驗失敗,拋出異常
    def validate_name(self, value):
        if 'g' in value.lower():  # 名字中不能出現g
            raise exceptions.ValidationError('名字非法!')
        return value

    # 全局鈎子:validate(self, 系統與局部鈎子校驗通過的所有數據)
    # 校驗規則:校驗通過返回原值,校驗失敗,拋出異常
    def validate(self, attrs):
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise exceptions.ValidationError({'pwd&re_pwd': '兩次密碼不一致'})
        return attrs

    # 要完成新增,需要自己重寫 create 方法
    def create(self, validated_data):
        # 盡量在所有校驗規則完畢之后,數據可以直接入庫
        return models.User.objects.create(**validated_data)
  • 視圖層
"""
1)book_ser = serializers.UserDeserializer(data=request_data)  # 數據必須賦值data
2)book_ser.is_valid()  # 結果為 通過 | 不通過
3)不通過返回 book_ser.errors 給前台,通過 book_ser.save() 得到新增的對象,再正常返回
"""
class User(APIView):
    # 只考慮單增
    def post(self, request, *args, **kwargs):
        # 請求數據
        request_data = request.data
        # 數據是否合法(增加對象需要一個字典數據)
        if not isinstance(request_data, dict) or request_data == {}:
            return Response({
                'status': 1,
                'msg': '數據有誤',
            })
        # 數據類型合法,但數據內容不一定合法,需要校驗數據,校驗(參與反序列化)的數據需要賦值給data
        book_ser = serializers.UserDeserializer(data=request_data)

        # 序列化對象調用is_valid()完成校驗,校驗失敗的失敗信息都會被存儲在 序列化對象.errors
        if book_ser.is_valid():
            # 校驗通過,完成新增
            book_obj = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.UserSerializer(book_obj).data
            })
        else:
            # 校驗失敗
            return Response({
                'status': 1,
                'msg': book_ser.errors,  #所有錯誤的信心都會藏在book_ser.errors中
                #將錯誤字段的信息返回給前台
            })

反序列化總結

視圖層:

  • 要把校驗的數據給(data= request.data)
  • .is_valid:結果為通過/不通過
  • .save():不通過返回.errors給前台,通過save()得到新增的對象,再正常返回。

反序列層:

  • 設置必填與選填序列化字段,設置校驗規則
  • 為需要額外校驗的字段提供局部鈎子函數,如果該字段不入庫,且不參與全局鈎子校驗,可以將值取出校驗
  • 為有聯合關系的字段們提供全局鈎子函數,如果某些字段不入庫,可以將值取出校驗
  • 重寫create方法,完成校驗通過的數據入庫工作,得到新增的對象


免責聲明!

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



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