DRF之序列化常用知識詳解
準備事項
# models.py from django.db import models class Publisher(models.Model): title = models.CharField(max_length=32) address = models.CharField(max_length=128) def __str__(self): return self.title class Author(models.Model): name = models.CharField(max_length=32) birth_date = models.DateField() gender = models.IntegerField(choices=((0,'male'),(1,'female')),default=0) email = models.EmailField(max_length=64) def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) pub_date = models.DateField() word_count = models.IntegerField() price = models.IntegerField(null=True,blank=True) def __str__(self): return self.title
# settings.py
INSTALLED_APPS = [
'app01',
'rest_framework',
]
序列化元件初見
利用HttpResponse返回json或者文字資料。
from rest_framework.views import APIView from django.shortcuts import HttpResponse from .models import Publisher import json from .models import Publisher from rest_framework import serializers class PublisherSerializer(serializers.Serializer): title = serializers.CharField() address = serializers.CharField() class PubliserView(APIView): """獲取所有出版社""" def get(self,request,*args,**kwargs): # 方式1: # publishers = Publisher.objects.all().values() # query set物件不能直接被序列化 # publishers = list(publishers) # return HttpResponse(json.dumps(publishers), content_type='application/json') # 方式2: from django.forms.models import model_to_dict # publishers = Publisher.objects.all() # temp = [] # for obj in publishers: # temp.append(model_to_dict(obj)) # return HttpResponse(json.dumps(temp), content_type='application/json') # 方式3 # from django.core import serializers # django的方法,與rest無關 # publishers = Publisher.objects.all() # ret = serializers.serialize('json',publishers) # return HttpResponse(ret) # 內容更多 # 方式4: publishers = Publisher.objects.all() ser = PublisherSerializer(instance=publishers,many=True) # 若例項是物件集合,則必須增加many=True print(ser.data) # [OrderedDict([('title', '長江出版社'), ('address', '武漢市武昌區')]), OrderedDict([('title', '人民出版社')] return HttpResponse(ser.data)
序列化欄位
類似django form。
# urls.py from app01.views import PubliserView, BookView url(r'^books/',BookView.as_view()), # views.py class BookView(APIView): def get(self, request, *args, **kwargs): book_list = Book.objects.all() from .my_serializer import BookSerializer ser = BookSerializer(instance=book_list, many=True) # 1、返回json格式的字串,對於瀏覽器相應內容會渲染到drf模板中,若是postman發的請求直接返回原始的資料 from rest_framework.response import Response return Response(ser.data) # 2、直接返回字串 # return HttpResponse(ser.data) # my_serializer.py from rest_framework import serializers class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) pub_date = serializers.DateField() word_count = serializers.IntegerField() # 一對多使:用source屬性 publisher = serializers.CharField(source='publisher.address') # 可以指定關聯表的欄位 price = serializers.IntegerField() # 針對多對多欄位 # authors = serializers.CharField(source="authors.all") authors = serializers.SerializerMethodField() def get_authors(self,obj): # print(obj) authors = list(obj.authors.all().values_list('name')) # [('蔣勳',), ('易中天',)] # authors = list(obj.authors.all().values('name')) # [{'name': '蔣勳'}, {'name': '易中天'}] authors = [item[0] for item in authors if item] return authors # 本質 ''' book_list = BookSerializer(book_list,many=True) temp = [] for obj in book_list: temp.append({ "title":str(obj.title), "price":obj.price, "pub_date":str(obj.pub_date), "word_count":obj.word_count, "publisher":str(obj.publisher), "authors":str(get_authors(obj)), # 多對多欄位 }) '''
ModelSerializer
類似與django的model-form。
作用:
將query_set轉換成json資料
def get(self,request): publishers = Publisher.objects.all() ser = PublisherSerializer(instance=publishers,many=True) # 若例項是物件集合,則必須增加many=True return Response(ser.data)
將 model物件 轉換成json資料
def get(self, request, pid): p_obj = Publisher.objects.filter(pk=int(pid)).first() ps = PublisherSerializer(instance=p_obj) return Response(ps.data)
3、做資料校驗,將json資料>>>成queryset或者model物件>>>記錄:
```python
def post(self, request):
bs = BookSerializers(data=request.data)
# 做校驗
if bs.is_valid():
# 轉換成model物件
bs.save() # 把資料儲存到資料庫中(會有反序列化操作),.save()中有 create()方法
return Response(bs.data)
else:
return HttpResponse(bs.errors) # bs.errors 表示 錯誤資訊
```
語法例項:
from .models import *
class BookSerializer(serializers.ModelSerializer):
"""
僅適用於展示欄位
"""
# 過載預設的欄位
publisher = serializers.CharField(source='publisher.address') # 可以指定關聯表的欄位
price = serializers.IntegerField()
# 針對多對多欄位
authors = serializers.SerializerMethodField()
def get_authors(self,obj):
# print(obj)
authors = list(obj.authors.all().values_list('name')) # [('蔣勳',), ('易中天',)]
# authors = list(obj.authors.all().values('name')) # [{'name': '蔣勳'}, {'name': '易中天'}]
authors = [item[0] for item in authors if item]
return authors
class Meta:
model = Book
fields = '__all__'
# 對於多餘多對多和一對多預設使用pk,一般為id
depth = 1
'''
# 增加前
[{
"id": 2,
"title": "蔣勳說唐詩",
"pub_date": "2012-02-07",
"word_count": 12,
"price": 34,
"publisher": 1,
"authors": [
1
]
},
# 增加後
[
{
"id": 2,
"title": "蔣勳說唐詩",
"pub_date": "2012-02-07",
"word_count": 12,
"price": 34,
"publisher": {
"id": 1,
"title": "長江出版社",
"address": "武漢市武昌區"
},
"authors": [
{
"id": 1,
"name": "蔣勳",
"birth_date": "1956-10-12",
"gender": 0,
"email": "[email protected]"
}
]
'''
ModelSerializer跨表取資料
1、對於OneToOne、Foreignkey、choices欄位可以使用source取出相關資訊:
class CourseSerializer(serializers.ModelSerializer):
# choices欄位
degree = serializers.CharField(source='get_degree_display')
# ForeignKey欄位
teacher = serializers.CharField(source='teacher.name')
class Meta:
model = Course
fields = '__all__'
2、對於ManyToMany欄位,例如:
class BookSerializers(serializers.ModelSerializer):
authors = serializers.SerializerMethodField()
publisher = serializers.CharField(source='publisher.title')
class Meta:
model = Book
fields = "__all__" # 可選擇顯示欄位
# exclude = ['price',] # 排除欄位
def get_authors(self,obj):
query_set = obj.authors.all()
return [{'name':obj.name} for obj in query_set]
{
"id": 2,
"authors": [
{
"name": "蔣勳"
}
],
"publisher": "長江出版社",
"title": "蔣勳說唐詩",
"pub_date": "2012-02-07",
"word_count": 12,
"price": 34
}
過載create方法
增加物件記錄。
from .my_serializer import BookSerializers
class BookView(APIView):
def post(self, request, *args, **kwargs):
"""儲存提交的資料"""
bs = BookSerializers(data=request.data)
if bs.is_valid(): # 做校驗
print('validated_data>>>>>>',bs.validated_data) # 結果為OrderedDict物件
'''
OrderedDict([
('title', 'who am i'), ('pub_date', datetime.date(2012, 12, 12)), ('word_count', 12), ('price', 29),
('publisher', <Publisher: 長江出版社>), ('authors', [<Author: 蔣勳>, <Author: 易中天>])
])
'''
bs.save() # 把資料儲存到資料庫中(會有反序列化操作) # .save()中有 create()方法
print('data>>>>>>', bs.data) # 結果為字典
'''
{'id': 21, 'title': 'who am i', 'pub_date': '2012-12-12', 'word_count': 12, 'price': 29, 'publisher': 1, 'authors': [1, 2]}
'''
return Response(bs.data)
else:
return HttpResponse(bs.errors) # bs.errors 表示 錯誤資訊
# 1、使用預設的欄位,則無需定製
# 在postman中提交json格式的資料:{"title":"1212312!","pub_date":"2012-12-12","word_count":12,"price":29,"publisher":1,"authors":[1,2]}
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# 2、定製欄位後
class BookSerializers(serializers.ModelSerializer):
publisher = serializers.CharField(source='publisher.pk')
class Meta:
model = Book
fields = "__all__"
# exclude = ['authors',]
# depth=1
# 處理多對多欄位時需要重寫 save()中的 create()方法
def create(self, validated_data):
print('validated_data>>>>>>>',validated_data)
'''
{
'title': '鋼鐵是怎樣煉成的',
'pub_date': datetime.date(2012, 12, 12),
'word_count': 12, 'price': 29,
'publisher': <Publisher: 長江出版社>,
'authors': [<Author: 蔣勳>, <Author: 易中天>]
}
'''
book_obj = Book.objects.create(
title=validated_data['title'],
pub_date=validated_data['pub_date'],
word_count=validated_data['word_count'],
publisher_id=validated_data['publisher']['pk'], # 注意此處欄位名稱為publisher_id!!!
price=validated_data['price'],
)
print('book_obj',book_obj)
# authors = validated_data.pop('authors')
# obj = Book.objects.create(**validated_data)
book_obj.authors.add(*validated_data['authors'])
return book_obj
單條資料處理
對特定物件的刪、改、查操作。
# urls
url(r'^books/(?P<id>\d+)/$',BookDetailView.as_view()),
# views.py
class BookDetailView(APIView):
"""對特定書籍的檢視、修改和刪除操作"""
def get(self, request, id):
b_obj = Book.objects.filter(pk=int(id)).first()
bs = BookSerializers(instance=b_obj)
return Response(bs.data)
def put(self, request, id):
"""沒有對應的物件則更新,有則修改"""
b_obj = Book.objects.filter(pk=int(id)).first()
bs = BookSerializers(instance=b_obj,data=request.data)
if bs.is_valid(): # 資料需要填寫完整
bs.save()
return Response(bs.data)
else:
return HttpResponse(bs.errors)
def delete(self, request,id):
"""刪除指定的物件"""
b_obj = Book.objects.filter(pk=int(id)).first()
b_obj.delete()
return Response() # 返回空
例:postman進行put操作
現階段程式碼
urls
from django.conf.urls import url
from django.contrib import admin
from app01.views import PubliserView, BookView, BookDetailView,PubliserDetailView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^publishers/$',PubliserView.as_view()), # 新增/查詢所有
url(r'^publishers/(?P<pid>\d+)/$',PubliserDetailView.as_view()), # 編輯/新增/刪除
url(r'^books/$',BookView.as_view()), # 新增/查詢所有
url(r'^books/(?P<id>\d+)/$',BookDetailView.as_view()), # 編輯/新增/刪除
]
serializer
from rest_framework import serializers
from .models import *
class PublisherSerializer(serializers.ModelSerializer):
class Meta:
model = Publisher
fields = '__all__'
# depth = 1
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# exclude = ['authors',]
# depth=1
views
有部分重複程式碼,有待優化!
所有記錄資料的獲取和新增資料功能對應一個檢視。
單條資料的增加、編輯、刪除等功能對應一個檢視。
一個model類對應兩個檢視,都需手動新增。
from rest_framework.views import APIView
from django.shortcuts import HttpResponse
from .models import Publisher,Book
from rest_framework.response import Response
from .my_serializer import PublisherSerializer
from .my_serializer import BookSerializers
class PubliserView(APIView):
def get(self,request):
"""查詢並返回所有出版社"""
publishers = Publisher.objects.all()
ser = PublisherSerializer(instance=publishers,many=True) # 若例項是物件集合,則必須增加many=True
return Response(ser.data)
def post(self,request):
"""新增出版社"""
bs = PublisherSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
class BookView(APIView):
def get(self, request):
"""查詢所有書籍"""
book_list = Book.objects.all()
ser = BookSerializers(instance=book_list, many=True)
from rest_framework.response import Response
return Response(ser.data)
def post(self, request):
"""新增書籍記錄"""
bs = BookSerializers(data=request.data)
if bs.is_valid(): # 做校驗
bs.save() # 把資料儲存到資料庫中(會有反序列化操作) # .save()中有 create()方法
return Response(bs.data)
else:
return HttpResponse(bs.errors) # bs.errors 表示 錯誤資訊
class PubliserDetailView(APIView):
"""獲取所有出版社"""
def get(self, request, pid):
"""查詢並返回某一個的出版社資訊"""
p_obj = Publisher.objects.filter(pk=int(pid)).first()
ps = PublisherSerializer(instance=p_obj)
print(ps)
return Response(ps.data)
def put(self, request, pid):
"""修改或新增一條出版社資訊"""
p_obj = Publisher.objects.filter(pk=int(pid)).first()
ps = PublisherSerializer(instance=p_obj, data=request.data)
print('ps>>>>',ps)
if ps.is_valid(): # 資料需要填寫完整
ps.save()
return Response(ps.data)
else:
return HttpResponse(ps.errors)
def delete(self, request,pid):
"""刪除某一條出版社記錄"""
Publisher.objects.filter(pk=int(pid)).delete()
return Response() # 返回空
class BookDetailView(APIView):
def get(self, request, id):
"""查詢並返回某一本書籍資訊"""
b_obj = Book.objects.filter(pk=int(id)).first()
bs = BookSerializers(instance=b_obj)
return Response(bs.data)
def put(self, request, id):
"""修改或新增一條書籍資訊"""
b_obj = Book.objects.filter(pk=int(id)).first()
bs = BookSerializers(instance=b_obj,data=request.data)
if bs.is_valid(): # 資料需要填寫完整
bs.save()
return Response(bs.data)
else:
return HttpResponse(bs.errors)
def delete(self, request,id):
"""刪除某一條書籍記錄"""
b_obj = Book.objects.filter(pk=int(id)).first()
b_obj.delete()
return Response() # 返回空
API原始碼流程
從定義路由到使用者訪問到開始呼叫dispatch函式期間的原始碼流程。
# 1、url初始化前:
url(r'^publishers/$',PubliserView.as_view())
# 2.1、開始初始化,執行PubliserView.as_view()
class APIView(View):
@classmethod
def as_view(cls, **initkwargs):
# 1.2、開始呼叫父類的as_view方法
view = super(APIView, cls).as_view(**initkwargs) # view
view.cls = cls
view.initkwargs = initkwargs
return csrf_exempt(view)
class View(object):
# 2.2、返回View.view方法名
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
return view
# 3、url初始化後:
url(r'^publishers/$',View.view)
# 4、使用者開始url,則開始執行View.view()方法,傳入原始的request物件,並呼叫PubliserView的dispatch方法
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
# step 5:PubliserView的父類有dispatch方法
class PubliserView(APIView):
pass
class ApiView(View):
def dispatch(self, request, *args, **kwargs):
pass
# step 6:構建新的request物件
class ApiView(View):
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# 6.1
request = self.initialize_request(request, *args, **kwargs)
# 6.2
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# 6.3
class Request(object):
def __init__(...):
self._request = request
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
@property
def data(self):
if not _hasattr(self, '_full_data'):
# 開始封裝self._request._post、self._request._file、self._full_data
self._load_data_and_files()
return self._full_data
@property
def query_params(self):
return self._request.GET
@property
def POST(self):
# Ensure that request.POST uses our request parsing.
if not _hasattr(self, '_data'):
self._load_data_and_files()
if is_form_media_type(self.content_type):
return self._data
return QueryDict('', encoding=self._request._encoding)
@property
def FILES(self):
if not _hasattr(self, '_files'):
self._load_data_and_files()
return self._files
# 6.3.1
def _load_data_and_files(self):
if not _hasattr(self, '_data'):
self._data, self._files = self._parse()
if self._files:
self._full_data = self._data.copy()
self._full_data.update(self._files)
else:
self._full_data = self._data
if is_form_media_type(self.content_type):
self._request._post = self.POST
self._request._files = self.FILES
# 6.3.2
def is_form_media_type(media_type):
"""
Return True if the media type is a valid form media type.
"""
base_media_type, params = parse_header(media_type.encode(HTTP_HEADER_ENCODING))
return (base_media_type == 'application/x-www-form-urlencoded' or
base_media_type == 'multipart/form-data')
相關推薦
DRF之序列化常用知識詳解
準備事項 # models.py from django.db import models class Publisher(models.Model): title = models.CharField(max_length=32) address = models.CharField(m
C#中Serializable序列化實例詳解
磁盤 close ear 但是 如果 mat 更新數據 eat 新的 本文實例講述了C#中Serializable序列化。分享給大家供大家參考。具體分析如下: 概述: 序列化就是是將對象轉換為容易傳輸的格式的過程,一般情況下轉化打流文件,放入內存或者IO文件 中。例如,可
DRF之序列化
獲取 values pat 沒有 date fir 2-0 choices ron 目錄 準備事項 序列化組件初見 序列化字段 ModelSerializer 重載create方法 單條數據處理 現階段代碼 準備事項 # models.py from django.db
Java中的序列化Serialable高階詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
drf 之 序列化器 大法 2
我們在django shell中來學習序列化器的使用。python manage.py shell 1 基本使用1) 先查詢出一個圖書物件from booktest.models import BookInfo book = BookInfo.objects.get(id=
Django序列化元件Serializers詳解
本文主要系統性的講解django rest framwork 序列化元件的使用,基本看完可以解決工作中序列化90%的問題,寫作參考官方文件https://www.django-rest-framework.org/api-guide/serializers/#modelserializer,
linux零基礎學習之Linux sed 命令常用操作詳解
延伸 進行 數據 12px -i 空白 字符串 options 信息 sed是Linux系統中一個很好的文件處理工具,可以對數據進行替換、刪除、新增以及選取等操作,使用起來也十分方面,以下是全面的sed操作介紹。sed命令行格式:sed [options] 'com
【資料結構必備基礎知識】之圖的基本概念詳解
一、前言 從今天開始就給大家分享有關於圖的概念和程式碼啦,不知道大家有沒有看夠樹的相關內容呢?以後還會慢慢給大家再分享的,程式碼要一遍一遍過,一輪一輪學習。第一輪樹就先到這裡,等第二輪還會給大家分享的。 圖應該是資料結構中處於霸王地位的一部分了,圖會涉及到圖論的相關知識,咱們現在還涉及不
分享知識-快樂自己:Hibernate框架常用API詳解
1):Configuration配置物件 Configuration用於載入配置檔案。 1): 呼叫configure()方法,載入src下的hibernate.cfg.xml檔案 Configuration conf = new Configuration().configure(); 2)
drf-序列化元件 rest-framework之序列化元件
rest-framework之序列化元件 一 Django自帶序列化元件 二 rest-framework序列化之Serializer 三 rest-framework序列化之ModelSerializer 四 生成hy
如何使用DRF的序列化器之反序列化
驗證資料:使用序列化器進行反序列化時,需要對資料進行驗證後,才能獲取驗證成功的資料或儲存成模型類物件。 在獲取反序列化的資料前,必須呼叫is_valid()方法進行驗證,驗證成功返回True,否則返回False。is_valid()方法還可以在驗證失敗時丟擲異常serializers.Valid
如何使用DRF的序列化器之序列化
DRF兩大利器為Serizlizer序列化器和檢視,而序列化器又分為序列化和反序列化,本篇文章首先來看下DRF序列化器的常用序列化方法。 首先來看使用Django開發REST介面時的表現,示例程式碼如下: # views.py from datetime import datetime
資料結構與演算法分析之----各種常用排序詳解
package cn.qunye.Sort_排序; import java.util.ArrayList; import java.util.List; /** * 合併排序: * 將待排序元素分成大小大致相同的兩個子集合,分別對兩個子集進行合併排序,最終將排好序的子集合併成所要求的排好序的集合 *
(七) RabbitMQ實戰教程(面向Java開發人員)之RabbitMQ常用屬性詳解
RabbitMQ常用屬性詳解 Alternate Exchange Alternate Exchange簡稱AE,當訊息不能被正確路由時,如果交換機設定了AE則訊息會被投遞到AE中,如果存在AE鏈則會按此繼續投遞,直到訊息被正確路由或AE鏈結束訊息被
Linux基礎知識之chattr和lsattr命令詳解
有時候你發現通過root使用者都不能修改某個檔案,大部分原因是曾經用chattr命令鎖定該檔案了。chattr命令的作用很大,其中一些功能是由Linux核心版本來支援的,不過現在生產絕大部分跑的linux系統都是2.6以上核心。通過chattr命令修改屬效能夠提高系統的安全性,但是它並不適合所有的目
Zookeeper之常用API詳解
1、建立ZNode ①命令列方式 在根目錄下建立“FZnode"節點並存儲資料”First Znode": create /FZnode "First Znode" 在根目錄下建立
《深入理解Spark》之Spark常用運算元詳解(java版+spark1.6.1)
最近公司要用Java開發Spark專案,以前用的是Scala語言,今天就把Spark常用的運算元使用java語言實現了一遍 XML Code 1 2 3 4 5 6 7 8 9 10 11 12
正則表示式知識詳解之匹配開頭或結尾 (java版示例)
示例功能: 1、匹配字串的開頭 2、匹配字串的結尾 package com.songguoliang.regex; import java.util.regex.Matcher; imp
黑馬程式設計師——常用API詳解之Object、Scanner、String
------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! ------- A:Object類 Object類是所有類的根類,其所有的方法為所有類所共有,所以很多類的基本功能都是依賴於Object實現的。 如: 無參構造方法(Object只有無參
DRF Django REST framework 之 序列化(三)
Django 原生 serializer (序列化) 匯入模組 from django.core.serializers import serialize 獲取 queryset 對 queryset 進行序列化 將序列化之後的資料