1、單表的GET和POST:
使用serializers序列化,針對每個表,須要單獨寫函數。通常會寫在views.py裏面,可是這樣作,會致使整個文件代碼過長。須要分離出來!django
在app01(應用名)目錄下,建立文件app01_serializers.py,表示自定義序列化api
from app01 import models from rest_framework import serializers # 序列化評論的類 class CommentSerializer(serializers.ModelSerializer): class Meta: model = models.Comment # Comment表 fields = "__all__" # 序列化全部字段 depth = 2 # 深度爲2
views.py中app
from rest_framework.views import APIView from app01 import app01_serializers # 導入自定義的序列化 class Comment(APIView):
def get(self, request): res = {"code":0} # 默認狀態 all_comment = models.Comment.objects.all() # print(all_comment) # 序列化,many=True表示返回多條 ser_obj = app01_serializers.CommentSerializer(all_comment, many=True) res["data"] = ser_obj.data return JsonResponse(res)
2、Response
Rest framework 引入了Response
對象,它是一個TemplateResponse
類型,並根據客戶端需求正確返回須要的類型。ide
使用前,須要導入模塊Response函數
from rest_framework.response import Response
舉例:post
修改視圖Comment中的get方法,將JsonResponse改爲Responseui
from rest_framework.views import APIView from app01 import app01_serializers # 導入自定義的序列化 from rest_framework.response import Response
# Create your views here. class Comment(APIView): def get(self, request): res = {"code":0} # 默認狀態 all_comment = models.Comment.objects.all() # print(all_comment) # 序列化,many=True表示返回多條 ser_obj = app01_serializers.CommentSerializer(all_comment, many=True) res["data"] = ser_obj.data return Response(res)
3、serializers校驗
舉例:判斷空數據url
修改views.py,添加post邏輯代碼。注意:使用is_valid校驗spa
from rest_framework.views import APIView from app01 import app01_serializers # 導入自定義的序列化 from rest_framework.response import Response # Create your views here. class Comment(APIView): def get(self, request): res = {"code":0} # 默認狀態 all_comment = models.Comment.objects.all() # print(all_comment) # 序列化,many=True表示返回多條 ser_obj = app01_serializers.CommentSerializer(all_comment, many=True) res["data"] = ser_obj.data return Response(res) def post(self, request): res = {"code": 0} # 去提交的數據 comment_data = self.request.data # 對用戶提交的數據作校驗 ser_obj = app01_serializers.CommentSerializer(data=comment_data) if ser_obj.is_valid(): # 表示數據沒問題,能夠建立 pass else: # 表示數據有問題 res["code"] = 1 res["error"] = ser_obj.errors return Response(res)
使用postman發送一個空數據的post請求rest
它返回This field is required,表示次字段不能爲空!
錯誤信息中文顯示
修改app01_serializers.py,使用extra_kwargs指定錯誤信息
from app01 import models from rest_framework import serializers # 序列化評論的類 class CommentSerializer(serializers.ModelSerializer): class Meta: model = models.Comment # Comment表 fields = "__all__" # 序列化全部字段 depth = 2 # 深度爲2 # 定義額外的參數 extra_kwargs = { "content": { "error_messages": { "required": '內容不能爲空', } }, }
重啓django,從新發送空的post請求
4、外鍵的GET和POST
序列化校驗
上面雖然只發送了content參數,就讓經過了,顯然不合理!爲何呢?
由於app01_comment表有2個字段,content和article。這2個字段都應該校驗纔對!
由於serializers默認校驗時,排除了外鍵字段。好比article
要對外鍵進行校驗,必須在extra_kwargs中指定外鍵字段
修改app01_serializers.py,注意關閉depth參數
當序列化類MATE中定義了depth時,這個序列化類中引用字段(外鍵)則自動變爲只讀,因此進行更新或者建立操做的時候不能使用此序列化類
大概意思就是,使用了depth參數,會忽略外鍵字段
完整代碼以下:
from app01 import models from rest_framework import serializers # 序列化評論的類 class CommentSerializer(serializers.ModelSerializer): class Meta: model = models.Comment # Comment表 fields = "__all__" # 序列化全部字段 # depth = 2 # 深度爲2 # 定義額外的參數 extra_kwargs = { "content": { "error_messages": { "required": '內容不能爲空', } }, "article": { "error_messages": { "required": '文章不能爲空' } } }
再次發送post請求,仍是隻有一個參數content
查看執行結果:
發送正確的2個參數
查看結果
read_only=True
read_only:True表示不容許用戶本身上傳,只能用於api的輸出。若是某個字段設置了read_only=True,那麼就不須要進行數據驗證,只會在返回時,將這個字段序列化後返回
舉例:容許article不校驗
修改app01_serializers.py,加入一行代碼
article = serializers.SerializerMethodField(read_only=True)
from app01 import models from rest_framework import serializers # 序列化評論的類 class CommentSerializer(serializers.ModelSerializer): article = serializers.SerializerMethodField(read_only=True) class Meta: model = models.Comment # Comment表 fields = "__all__" # 序列化全部字段 # depth = 2 # 深度爲2 # 定義額外的參數 extra_kwargs = { "content": { "error_messages": { "required": '內容不能爲空', } }, "article": { "error_messages": { "required": '文章不能爲空' } } }
保存POST數據
修改views.py,在post方法中,將pass改爲ser_obj.save(),完整代碼以下:
from rest_framework.views import APIView from app01 import app01_serializers # 導入自定義的序列化 from rest_framework.response import Response # Create your views here. class Comment(APIView): def get(self, request): res = {"code":0} # 默認狀態 all_comment = models.Comment.objects.all() # print(all_comment) # 序列化,many=True表示返回多條 ser_obj = app01_serializers.CommentSerializer(all_comment, many=True) res["data"] = ser_obj.data return Response(res) def post(self, request): res = {"code": 0} # 去提交的數據 comment_data = self.request.data # 對用戶提交的數據作校驗 ser_obj = app01_serializers.CommentSerializer(data=comment_data) if ser_obj.is_valid(): # 表示數據沒問題,能夠建立 ser_obj.save() else: # 表示數據有問題 res["code"] = 1 res["error"] = ser_obj.errors return Response(res)
修改app01_serializers.py,註釋掉read_only=True
發送2個正確的參數
查看app01_comment表記錄,發現多了一條記錄
爲何直接save,就能夠保存了呢?
由於它將校驗過的數據傳過去了,就好像form組件中的self.cleaned_data同樣
本質上仍是調用ORM的create()方法
5、非serializer 的驗證條件
好比重置密碼、修改密碼都須要手機驗證碼。可是用戶 model 裏面並無驗證碼這個選項
須要使用validate,用於作校驗的鉤子函數,相似於form組件的clean_字段名
使用時,須要導入模塊,用來輸出錯誤信息
from rest_framework.validators import ValidationError
局部鉤子
validate_字段名,表示局部鉤子。
舉例:評論的內容中,不能包含 "草"
修改app01_serializers.py,校驗評論內容
from app01 import models from rest_framework import serializers from rest_framework.validators import ValidationError # 序列化評論的類 class CommentSerializer(serializers.ModelSerializer): # article = serializers.SerializerMethodField(read_only=True) # 用於作校驗的鉤子函數,相似於form組件的clean_字段名 def validate_content(self, value): if '草' in value: raise ValidationError('不符合社會主義核心價值觀!') else: return value class Meta: model = models.Comment # Comment表 fields = "__all__" # 序列化全部字段 # depth = 2 # 深度爲2 # 定義額外的參數 extra_kwargs = { "content": { "error_messages": { "required": '內容不能爲空', } }, "article": { "error_messages": { "required": '文章不能爲空' } } }
使用postman發送包含關鍵字的評論
查看返回結果:
全局鉤子
validate,表示全局鉤子。
好比在用戶註冊時,咱們須要填寫驗證碼,這個驗證碼只須要驗證,不須要保存到用戶這個Model中:
def validate(self, attrs): del attrs["code"] return attrs
6、超連接的序列化
HyperlinkedModelSerializer
類相似於ModelSerializer
類,不一樣之處在於它使用超連接來表示關聯關係而不是主鍵。
默認狀況下序列化器將包含一個url
字段而不是主鍵字段。
url字段將使用HyperlinkedIdentityField
字段來表示,模型的任何關聯都將使用HyperlinkedRelatedField
字段來表示。
你能夠經過將主鍵添加到fields
選項中來顯式的包含,例如:
class AccountSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Account fields = ('url', 'id', 'account_name', 'users', 'created')
絕對和相對URL
當實例化一個HyperlinkedModelSerializer
時,你必須在序列化器的上下文中包含當前的request
值,例如:
serializer = AccountSerializer(queryset, context={'request': request})
這樣作將確保超連接能夠包含恰當的主機名,一邊生成徹底限定的URL,例如:
http://api.example.com/accounts/1/
而不是相對的URL,例如:
/accounts/1/
若是你真的要使用相對URL,你應該明確的在序列化器上下文中傳遞一個{'request': None}
。
需求:要求api返回結果中,school展現的是超連接
修改app01_urls.py,增長路由
urlpatterns = [ # 文章 url(r'article/', views.Article.as_view()), url(r'article/(?P<pk>\d+)', views.ArticleDetail.as_view(), name='article-detail'), # 學校 url(r'school/(?P<id>\d+)', views.SchoolDetail.as_view(), name='school-detail'), # 評論 url(r'comment/', views.Comment.as_view()), ]
指定name是爲作反向連接,它能解析出絕對url
序列化
修改app01_serializers.py
from app01 import models from rest_framework import serializers from rest_framework.validators import ValidationError # 序列化評論的類 class CommentSerializer(serializers.ModelSerializer): # article = serializers.SerializerMethodField(read_only=True) # 用於作校驗的鉤子函數,相似於form組件的clean_字段名 def validate_content(self, value): if '草' in value: raise ValidationError('不符合社會主義核心價值觀!') else: return value #全局的鉤子 def validate(self, attrs): # self.validated_data # 通過校驗的數據 相似於form組件中的cleaned_data # 全局鉤子 pass class Meta: model = models.Comment # Comment表 fields = "__all__" # 序列化全部字段 # depth = 2 # 深度爲2 # 定義額外的參數 extra_kwargs = { "content": { "error_messages": { "required": '內容不能爲空', } }, "article": { "error_messages": { "required": '文章不能爲空' } } } # 文章的序列化類 class ArticleModelSerializer(serializers.ModelSerializer): class Meta: model = models.Article # 綁定的ORM類是哪個 fields = "__all__" # ["id", "title", "type"] # depth = 1 # 官方推薦不超過10層 # 文章超連接序列化 class ArticleHyperLinkedSerializer(serializers.HyperlinkedModelSerializer): school = serializers.HyperlinkedIdentityField(view_name='school-detail', lookup_url_kwarg='id') class Meta: model = models.Article # 綁定的ORM類是哪個 fields = ["id", "title", "type", "school"] # 學校的序列化 class SchoolSerializer(serializers.ModelSerializer): class Meta: model = models.School fields = "__all__"
參數解釋:
source 表示來源
lookup_field 表示查找字段,默認使用的pk, 指的是反向生成URL的時候, 路由中分組命名匹配的value
lookup_url_kwarg 表示路由查找的參數,pk表示主鍵, 默認使用pk,指的是反向生成URL的時候 路由中的分組命名匹配的key
view_name 它是指urls定義的name值,必定要一一對應。 默認使用 表名-detail
修改views.py,增長視圖函數
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
from rest_framework.views import APIView from app01 import app01_serializers # 導入自定義的序列化 from rest_framework.response import Response # Create your views here. class Comment(APIView): def get(self, request): res = {"code":0} # 默認狀態 all_comment = models.Comment.objects.all() # print(all_comment) # 序列化,many=True表示返回多條 ser_obj = app01_serializers.CommentSerializer(all_comment, many=True) res["data"] = ser_obj.data return Response(res) def post(self, request): res = {"code": 0} # 去提交的數據 comment_data = self.request.data # 對用戶提交的數據作校驗 ser_obj = app01_serializers.CommentSerializer(data=comment_data) if ser_obj.is_valid(): # 表示數據沒問題,能夠建立 ser_obj.save() else: # 表示數據有問題 res["code"] = 1 res["error"] = ser_obj.errors return Response(res) # return HttpResponse("建立新評論") def put(self, request): return HttpResponse("修改評論") def delete(self, request): return HttpResponse("刪除評論") # 文章CBV class Article(APIView): def get(self, request): res = {"code": 0} all_article = models.Article.objects.all() ser_obj = app01_serializers.ArticleHyperLinkedSerializer(all_article, many=True, context={'request': request}) res["data"] = ser_obj.data return Response(res) def post(self, request): res = {"code": 0} ser_obj = app01_serializers.ArticleModelSerializer(data=self.request.data) if ser_obj.is_valid(): ser_obj.save() else: res["code"] = 1 res["error"] = ser_obj.errors return Response(res) # 文章詳情CBV class ArticleDetail(APIView): def get(self, request, pk): res = {"code": 0} article_obj = models.Article.objects.filter(pk=pk).first() # 序列化 ser_obj = app01_serializers.ArticleHyperLinkedSerializer(article_obj, context={'request': request}) res["data"] = ser_obj.data return Response(res) # 學校詳情CBV class SchoolDetail(APIView): def get(self, request, id): res = {"code": 0} school_obj = models.School.objects.filter(pk=id).first() ser_obj = app01_serializers.SchoolSerializer(school_obj, context={'request': request}) res["data"] = ser_obj.data return Response(res)
參數解釋:
id 表示參數,它和url的參數,是一一對應的
content 表示上下文
重啓django項目,訪問網頁:
http://127.0.0.1:8000/api/article/1
效果以下:
點擊第一個連接,效果以下: