#?DRF?serializers小結(jié)

DRF serializers小結(jié)


django settings文件查找順序

? django查詢變量的順序是先從用戶的settings里面查找,然后在global_settings中查找,如果用戶desettings文件中找到了,則不會繼續(xù)查找global_settings中的配置信息。

django原生的serializer

from django.db import models

# Create your models here.


class Courses(models.Model):
    title = models.CharField(max_length=32)
    description = models.CharField(max_length=128)
class CoursesView(View):
    def get(self, request):
        courses = list()

        for item in Courses.objects.all():
            course = {
                "title": item.title,
                "description": item.description
            }

            courses.append(course)

        return HttpResponse(json.dumps(courses, ensure_ascii=False))

? 通過上面的方式,我們定義了符合規(guī)范的返回數(shù)據(jù),加上符合規(guī)范的url,我們完成了手動完成了REST開發(fā),但是效率不高。

from django.core.serializers import serialize

class StudentView(APIView):
    def get(self, request):
        origin_Student = Student.objects.all()
        serialized_students = serialize("json", origin_students)
        return HttpResponse(serialized_students)

? 使用方法非常簡單,導入模塊之后,價格需要的格式和queryset傳給serialize進行序列化,然后返回序列化后的數(shù)據(jù)。

? 如果你的項目僅僅只需要序列化一部分數(shù)據(jù),不需要用到諸如認證、權(quán)限等其他功能,可以使用django原生的serializer,否則建議使用DRF。

解析器組件

from django.http import JsonResponse
from rest_framework.view import APIView
from rest_framework.parsers import JSONParser, FormParser
# Create your views here.


class LoginView(APIView):
    def get(self, request):
        return render(request, 'parserver/logoin.html')
    def post(self, request):
        # request 是被drf封裝的新的對象,是基于django的request
        # request.data是一個property,用于對數(shù)據(jù)進行校驗
        # request.data最后會找到self.parser_classes中的解析器來實現(xiàn)對數(shù)據(jù)進行解析
        print(requet.data)  # {'username':'Gavin', 'password':123}
        return JsonResponse({'status_code':200, 'code':'ok'})

? 使用步驟如下:

  1. ? from rest_framework.views import APIView
  2. ? 繼承APIView
  3. ? 直接使用request.data就可以獲取Json數(shù)據(jù)

? 如果只需要解析Json數(shù)據(jù),不允許其他類型的數(shù)據(jù)請求,可以這樣做:

  1. ? from rest_framework.views import JsonParse
  2. ? 給視圖類定義一個parser_classes變量,值為列表類型[JsonParser]
  3. ? 如果parser_classes = [] ,那就不處理任何數(shù)據(jù)類型的請求了

序列化組件的使用

from django.db import models
# create your models here.


class Publich(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_lenght=32)
    age = models.IntegerField()
    
    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()

    def __str__(self):
        return self.name  

    
 class Book(models.Model):
    title = models.CharField(max_length=32)
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')
通過序列化組件進行接口設(shè)計,首先設(shè)計url,以GET和POST為例
from django.ruls import re_path
from serializers import views
urlpatterns = [
    re_path(r'book/', views.BookView.as_view())
]
新建一個名為app_serializers.py的模塊,將所有的序列化的使用集中在這個模塊里,對程序 進行解耦:
# -*- coding: utf-8 -*-
from rest_framework import serializers

from .models import Book


class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=128)
    publish_date = serializers.DateTimeField()
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.CharField(max_length=32)
    authors = serializers.CharField(max_length=32)
接著,使用序列化組件,開始寫試圖類
from rest_framework.views import APIView
from rest_framework.response import Response

# 當前app中的模塊
from .models import Book
# 導入序列化器
from .app_serializer import BookSerializer

class BookView(APIView):
    def get(self, request):
        origin_books = Book.objects.all()
        serialized_books = BookSerializer(origin_books, many=True)
        return Response(serialized_books.data)
定義好model和url之后可使用序列化組價的步驟:
  1. 導入序列化組件:from rest_framework import serializers

  2. 定義序列化類:繼承serializerrs.Serializer(建議單獨創(chuàng)建一個專用模塊來存放所有的序列化類)class BookSerializer(serializers.Serializer):pass

  3. 定義需要返回的字段:(字段類型可以與model中的類型不一致,參數(shù)也可以調(diào)整),字段名稱必須與model中的一致。

  4. 在GET接口或幾種,獲取QuerySet

  5. 開始序列化:將QuerySet作為第一個參數(shù)傳給序列化器類,many默認為False,如果返回的數(shù)據(jù)是一個列表嵌套字典的多個對象那個集合,需要改為many=True

  6. 返回:將序列化對象的data屬性返回即可

    rest_framework.response的Response對象,它是DRF重新封裝的相應(yīng)對象。該對象在返回響應(yīng)數(shù)據(jù)的時候,會判斷客戶端類型,如果是瀏覽器,它會以web頁面的形式返回,如果是POSTMAN這一類的工具,就直接返回Json類型數(shù)據(jù)。

    此外,序列化類中的字段名也可以與model中的字段不一致,但是需要使用source參數(shù)來告訴組件原來的字段名,一般我們寫成一樣的就好了。

    class BookSerializer(serializers.Serializer):
        BookTitle = serializers.CharField(max_length=128, source="title")
        publishDate = serializers.DateTimeField()
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        # source也可以用于ForeignKey字段
        publish = serializers.CharField(max_length=32, source="publish.name")
        authors = serializers.CharField(max_length=32)
    

    那么多對多字段如何處理?如果將source參數(shù)定義為"authors.all",那么取出來的結(jié)果將是一個QuerySet,這樣的數(shù)據(jù)對前端并不是很友好,所以我們可以使用序列化器嵌套,或者這樣:

    class BookSerializer(serializers.Serializer):
        title = serializers.CharField(max_length=32)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        publishDate = serializers.DateField()
        publish = serializers.CharField()
        publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
        publish_email = serializers.CharField(max_length=32, read_only=True, source='publish.email')
        # authors = serializers.CharField(max_length=32, source='authors.all')
        authors_list = serializers.SerializerMethodField()
    
        def get_authors_list(self, authors_obj):
            authors = list()
            for author in authors_obj.authors.all():
                authors.append(author.name)
    
            return authors
    

    注意,get_必須與字段名稱一致,否則會報錯。

    # -*- coding: utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    # 當前app中的模塊
    from .models import Book
    from .app_serializer import BookSerializer
    
    # Create your views here.
    
    
    class BookView(APIView):
        def get(self, request):
            origin_books = Book.objects.all()
            serialized_books = BookSerializer(origin_books, many=True)
    
            return Response(serialized_books.data)
    
        def post(self, request):
            verified_data = BookSerializer(data=request.data)
    
            if verified_data.is_valid():
                book = verified_data.save()
                # 可寫字段通過序列化添加成功之后需要手動添加只讀字段
                authors = Author.objects.filter(nid__in=request.data['authors'])
                book.authors.add(*authors)
    
                return Response(verified_data.data)
            else:
                return Response(verified_data.errors)
    

    ?

    POST接口的實現(xiàn)步驟:
    1. url定義:需要為post新增url,根據(jù)規(guī)范,url定位資源,http請求方式定義用戶行為

    2. 定義post方法:在視圖類中定義post方法

    3. 開始序列化:通過我們定義的序列化類,創(chuàng)建一個序列化對象,傳入?yún)?shù)data=request.data(application/json)數(shù)據(jù)

    4. 校驗數(shù)據(jù):通過實例對象的is_valid()方法,對請求數(shù)據(jù)的合法性進行校驗

    5. 保存數(shù)據(jù):調(diào)用save()方法,將數(shù)據(jù)插入數(shù)據(jù)庫

    6. 插入數(shù)據(jù)到多對多關(guān)系表:如果有多對多字段,手動插入數(shù)據(jù)到多對多關(guān)系表

    7. 返回:將插入的對象返回

      因為多對多字關(guān)系字段是沃恩自定義的,而且必須這樣定義,返回的數(shù)據(jù)才有意義,而用戶插入數(shù)據(jù)的時候,serrializers.Serializer沒有實現(xiàn)create,我們必須手動插入數(shù)據(jù),像這樣:

      # 第二步, 創(chuàng)建一個序列化類,字段類型不一定要跟models的字段一致
    class BookSerializer(serializers.Serializer):
      # nid = serializers.CharField(max_length=32)
        title = serializers.CharField(max_length=128)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        publish = serializers.CharField()
        # 外鍵字段, 顯示__str__方法的返回值
        publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
        publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city')
        # authors = serializers.CharField(max_length=32) # book_obj.authors.all()
      
        # 多對多字段需要自己手動獲取數(shù)據(jù),SerializerMethodField()
        authors_list = serializers.SerializerMethodField()
      
        def get_authors_list(self, book_obj):
            author_list = list()
      
            for author in book_obj.authors.all():
                author_list.append(author.name)
      
            return author_list
      
         def create(self, validated_data):
            # {'title': 'Python666', 'price': Decimal('66.00'), 'publish': '2'}
             validated_data['publish_id'] = validated_data.pop('publish')
             book = Book.objects.create(**validated_data)
             return book
      
          def update(self, instance, validated_data):
              # 更新數(shù)據(jù)會調(diào)用該方法
              instance.title = validated_data.get('title', instance.title)
              instance.publishDate = validated_data.get('publishDate', instance.publishDate)
              instance.price = validated_data.get('price', instance.price)
              instance.publish_id = validated_data.get('publish', instance.publish.nid)
      
              instance.save()
      
              return instance
  這樣就比較復雜,那么我們**如何讓序列化類自動插入數(shù)據(jù)**?如果字段很多,那么寫序列化類也會成為一種負擔,有沒有更加簡單的方式呢?

  ~~~python
  class BookSerializer(serializers.ModelSerializer):
      class Meta:
          model = Book
  
          fields = ('title',
                    'price',
                    'publish',
                    'authors',
                    'author_list',
                    'publish_name',
                    'publish_city'
                    )
          extra_kwargs = {
              'publish': {'write_only': True},
              'authors': {'write_only': True}
          }
  
      publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
      publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city')
  
      author_list = serializers.SerializerMethodField()
  
      def get_author_list(self, book_obj):
          # 拿到queryset開始循環(huán) [{}, {}, {}, {}]
          authors = list()
  
          for author in book_obj.authors.all():
              authors.append(author.name)
  
          return authors
  ~~~

  ##### 我們繼承了ModelSerializer而不是Serializer,**ModelSerializer對Serializer進行了擴展,添加了以下功能:**

  - **基于model自動創(chuàng)建一些字段**

  - **會自動生成一些驗證,比如unique_together驗證**

  - **包含了簡單的默認的create()和updata()**

  ~~~python
  class BookSerializer(serializers.ModelSerializer):
      class Meta:
          model = Book
          fields = ('title', 'price',)
          # fields = "__all__"
  ~~~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容