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'})
? 使用步驟如下:
- ? from rest_framework.views import APIView
- ? 繼承APIView
- ? 直接使用request.data就可以獲取Json數(shù)據(jù)
? 如果只需要解析Json數(shù)據(jù),不允許其他類型的數(shù)據(jù)請求,可以這樣做:
- ? from rest_framework.views import JsonParse
- ? 給視圖類定義一個parser_classes變量,值為列表類型[JsonParser]
- ? 如果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之后可使用序列化組價的步驟:
導入序列化組件:from rest_framework import serializers
定義序列化類:繼承serializerrs.Serializer(建議單獨創(chuàng)建一個專用模塊來存放所有的序列化類)class BookSerializer(serializers.Serializer):pass
定義需要返回的字段:(字段類型可以與model中的類型不一致,參數(shù)也可以調(diào)整),字段名稱必須與model中的一致。
在GET接口或幾種,獲取QuerySet
開始序列化:將QuerySet作為第一個參數(shù)傳給序列化器類,many默認為False,如果返回的數(shù)據(jù)是一個列表嵌套字典的多個對象那個集合,需要改為many=True
-
返回:將序列化對象的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)步驟:
url定義:需要為post新增url,根據(jù)規(guī)范,url定位資源,http請求方式定義用戶行為
定義post方法:在視圖類中定義post方法
開始序列化:通過我們定義的序列化類,創(chuàng)建一個序列化對象,傳入?yún)?shù)data=request.data(application/json)數(shù)據(jù)
校驗數(shù)據(jù):通過實例對象的is_valid()方法,對請求數(shù)據(jù)的合法性進行校驗
保存數(shù)據(jù):調(diào)用save()方法,將數(shù)據(jù)插入數(shù)據(jù)庫
插入數(shù)據(jù)到多對多關(guān)系表:如果有多對多字段,手動插入數(shù)據(jù)到多對多關(guān)系表
-
返回:將插入的對象返回
因為多對多字關(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__"
~~~