Django的serializers使用


Serializer

在這里通過一個驗證用戶身份的例子說明rest_framework中serializer.Serializer的使用。

編寫serializer

Serializer的使用不需要依賴於模型,所以可以不要編寫model,直接編寫serializer文件。

from rest_framework import serializers


class TestSerializer(serializers.Serializer):

    name = serializers.CharField(max_length=20, required=True)
    code = serializers.CharField(max_length=20, required=True)

編寫view

使用rest_framework的APIView編寫視圖,實現get和post方法

from django.http import HttpResponse, JsonResponse
from django.contrib.auth import authenticate
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

from school.serializers.school import TestSerializer


class TestView(APIView):

    def get(self, request):
        # 獲取auth中的用戶
        user = request.user
        if user.is_authenticated:   # is_superuser
            return HttpResponse(user.username + '已授權')
        return HttpResponse('未授權')

    def post(self, request):
        serializer = TestSerializer(data=request.data)

        if serializer.is_valid():
            username = serializer.validated_data.get("name", "")
            password = serializer.validated_data.get("code", "")

            # 調用authenticate方法
            user = authenticate(username=username, password=password)

            if user is not None:
                content = {
                    "status": True,
                    "message": "賬戶正確"
                }
                return JsonResponse(data=content, status=status.HTTP_200_OK)
            else:
                content = {
                    "status": False,
                    "message": "賬號或者密碼不正確"
                }
                return JsonResponse(data=content, status=status.HTTP_200_OK)
        else:
            return Response(data=serializer.errors)

使用django的View和rest_framework的APIView實現get和post方法時,無論是否顯式使用到request,都需要request參數,否則會出錯。

get

  • 首先通過request.user獲取auth信息
  • 然后根據is_authenticated或is_superuser等判斷auth信息是否符合要求。auth的用戶名和密碼可以通過request.user.username和request.user.password獲取。

post

在前面的get方法中並未用到serializer,只是獲取了auth信息。而在post方法中將serializer結合post參數驗證user信息。

  • 首先,通過post的參數創建一個序列化類實例。
  • 然后,判斷序列化實例是否有效,無效則直接返回序列化錯誤信息
  • 當序列化有效時,通過serializer.validated_data.get()獲取post數據參數。注意,只能獲取到serializer類中定義的字段值。在該例子中,name和code在TestSerializer中有定義,當post參數名為name和code時可以獲取,否則不能獲取。比如,當post有個參數是username時,使用serializer.validated_data.get("username", "")不能得到username的參數值。
  • 最后使用authenticate驗證,根據驗證結果返回相關信息。

ModelSerializer

ModelSerializer的使用需要依賴於已有model模型,常用來編寫api。這里只介紹ModelSerializer的使用,view方面不作說明。

創建模型

首先需要創建模型,這里拿一個外鍵關聯的例子來說明。

from django.db import models


class School(models.Model):
    name = models.CharField(max_length=32, verbose_name="名稱")
    code = models.CharField(max_length=16, verbose_name="代碼")
    location = models.CharField(max_length=128, verbose_name="地址")


class Student(models.Model):
    name = models.CharField(max_length=32, verbose_name="姓名")
    age = models.IntegerField(verbose_name="年齡")
    school = models.ForeignKey(to=School,verbose_name="學校", on_delete=models.CASCADE)

這里,有兩個模型,Student模型通過school字段關聯School模型,on_delete=models.CASCADE表示刪除School實例時會級聯刪除Student實例。

序列化

由於School只有三個基本類型字段,所以這里以Student的序列化為例進行說明。

# -*- coding: utf-8 -*-
from rest_framework import serializers

from school.models import Student, School


class StudentSerializer(serializers.ModelSerializer):
    # 多對多時添加參數 many=True
    school = serializers.SlugRelatedField(read_only=False, slug_field="name", queryset=School.objects.all())
    # address = serializers.CharField(source="school.address", default=None)

    def create(self, validated_data):
        # some actions
        instance = super().create(validated_data)
        return instance

    def update(self, instance, validated_data):
        user = self.context['request'].user        # 請求的用戶
        username = self.context['request'].data.get('username')     # 請求的參數username
        instance.name = validated_data['name']      # 請求的參數name
        # some actions
        instance.save()
        return instance

    class Meta:
        model = Student
        fields = ('id', 'name', 'age', 'school')
        read_only_fields = ('id', 'age')

在這里值得注意的地方主要有三點:序列化外鍵字段、重寫create方法、重寫update方法。

  • 在序列化外鍵字段時,如果要使用被關聯對象的某個字段來代表該字段,可以使用SlugRelatedField。在多對多情況下還需要添加參數many=True。當然,也可以另起一個字段來展示被關聯對象某個字段的值,如
address = serializers.CharField(source="school.address", default=None)

除了上面的方法,還可以使用一個更通用的方法,可以序列化非模型中的字段或者外鍵的外鍵等。
使用SerializerMethodField通過定義方法序列化:

status = serializers.SerializerMethodField()

def get_status_verbose(self, obj):
	# obj表示當前模型對象
	return obj.get_status_display()
  • 重寫create方法有兩個參數,validated_data中是創建實例各字段的值,調用super().create(validated_data)即創建了實例,返回實例對象instance。我們可以在調用父類的create方法前后作一些處理,比如在調用之前對validated_data中的字段重新賦值。當在創建實例時,如果需要附帶自動創建日志實例時,可以將instance作為日志實例的外鍵創建日志實例。最后將創建的Student實例instance返回出去。

  • 重寫update方法有三個參數,instance是要修改的模型實例,validated_data是請求的參數。在update方法中,我們一般需要獲取相關的數據來修改模型的值,主要可以歸為三種。第一,獲取用戶信息,使用self.context['request'].user。第二,請求參數中的數據,但是參數的名稱與模型字段的名稱不一致,無法通過validated_data獲取,使用self.context['request'].data.get('username')獲取。第三,請求參數中與模型字段命名一致的數據,直接使用validated_data['name']獲取。獲取完數據后可以對instance的字段進行一些賦值操作,最后保存instance即可。


免責聲明!

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



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