首先介紹一下相關概念
序列化器(Serializer)
1. 自定義型: 繼承rest_framework.serializers.Serializer
2. 模型類型: 繼承rest_framework.serializers.ModelSerializer
創建Serializer對象
構造方法:Serializer(instance=None, data=empty, **kwarg)
參數1,序列化必須傳入的模型類對象
參數2,反序列化時把數據傳入data
額外參數:例如context={'XX':'XX'},可通過context屬性獲取, context上下文解析詳解上面官方文檔
序列化注意點:
1. 序列化時如果被序列化是多條查詢集,通過添加many=True,列表形式
如果關聯對象有多個,也可以在序列化器字段添加many=True
2. 如果模型類存在外鍵字段,處理方式如下:
①PrimaryKeyRelatedField,需設置read_only=True或queryser參數
被序列化后是關聯字段數據
②StringRelatedField,被序列化是關聯對象__str__返回值
③HyperlinkedRelatedField,需設置read_only,view_name
被序列化為關聯對象數據的API鏈接
④SlugRelateField,需設置read_only,slug_field
被序列化后是關聯對象的指定字段數據
⑤使用關聯對象的序列化器類的實例
⑥重寫to_representation 可修改被序列化后的返回值
反序列化
驗證:在反序列化時,對數據驗證,驗證成功后才可獲取數據或保存為模型類對象
①調用is_valid方法驗證,成功True,失敗False
②驗證失敗時,通過序列化器對象的errors屬性獲取錯誤信息,返回字典包含字段和字段錯誤,如果非字段錯誤,可修改配置中NON_FIELD_ERRORS_KEY來控制鍵名
③驗證成功時,通過序列化器對象的validated_date屬性獲取數據
注意點:帶參數raise_exception=True在反序列化時is_valid()方法在驗證失敗時拋出serializers.ValidationError,REST framework接收到此異常,會向前端返回HTTP 400 Bad Request響應。
自定義驗證行為:
1. validate_字段名:在序列化器中添加方法,方法名validate_字段名,參數為value,對value做校驗,raise
serializers.ValidationError('XXXX'),返回值value
2. validate:在序列化器中添加validate方法,可同時對多個字段進行驗證
參數為attrs,從attrs中獲取值,然后進行邏輯處理,拋出異常,返回值attrs
3.validator:在序列化器上方編寫函數,參數value,對value校驗,拋出異常
在序列化器字段中加入validator選項參數,為列表形式,值為函數名。
4.REST framework提供的validators:
UniqueValidator單字段唯一:字段中設置,參數為queryset
UniqueTogetherValidation聯合唯一:class Meta中設置,參數queryset和fields
保存:如果驗證成功,向基於validated_data完成數據對象的創建,可以通過create和update來實現
1.新建:在序列化器中重寫create方法,參數為validate_data,
返回值為模型類.objects.create(**validated_data)
2.更新:在序列化器中重寫update方法,參數instance即要更新的實例和validate_data
對validate_data字典獲取其值,對無傳遞值給予默認值 instance.字段,並賦給instance.字段,然后調用instance.save()提交,返回值instance
注意點:
①實現了create和update方法后,在反序列化時既可以序列化對象.save()返回數據對象實例並保存或更新到數據庫
②調用save時,如果有傳instance實例,則調用update方法更新數據,否則調用create方法新建數據。
③調用save可傳參,參數可從validated_data中獲取
④如果沒有傳遞所有required字段,會拋出驗證異常,可通過使用partial=True實現部分字段更新
模型類序列化器ModelSerializer
可基於模型類自動生成一系列字段,會自動生成valiators和實現了默認的create和update方法
ModelSerializer
ModelSerializer 類似於 ModelForm 提供了一些便捷的方法,使你可以自動對 Django Model 中包含的部分或所有字段序列化。
用法上 ModelSerializer 和 Serializer 基本相同,除下面幾點外:
- 在 Model 字段的基礎上自動生成序列化字段
- 自動生成對 unique_together 的 validators
- 自動包含基礎的 .create(), update() 的實現
關於序列化,之前在處理分頁時已經使用過了。
這次通過一個用戶信息列表及新增用戶介紹一下ModelSerializer 在項目中的具體應用。
其他項目配置相關不做介紹,從創建models開始
# models.py from django.db import models # Create your models here. class UserInfo(models.Model): '''用戶信息表''' # unique=True 限定唯一 username = models.CharField(verbose_name='用戶名',max_length=32,unique=True) # 表單提交可為空,數據庫存儲可為 NULL blank=True, null=True nickname = models.CharField(verbose_name='名稱', max_length=32,blank=True, null=True) telephone = models.CharField(max_length=11, blank=True, null=True, unique=True, verbose_name='手機號碼') email = models.EmailField(max_length=64,blank=True, null=True, unique=True,verbose_name='email') password = models.CharField(verbose_name='密碼', max_length=128) # 用戶項目分組 usergroup = models.CharField(verbose_name='用戶分組', max_length=128, null=True,blank=True) # 用戶類型 usertype = models.CharField(verbose_name='用戶類型', max_length=128, null=True,blank=True) avatar = models.ImageField(verbose_name='頭像', upload_to='avatar', default="/avatar/default.png", null=True,blank=True) status = models.IntegerField(verbose_name='用戶狀態',default=1) userPermissions = models.CharField(verbose_name='用戶權限',max_length=1024,null=True,blank=True) createTime = models.DateTimeField(verbose_name='創建時間', auto_now_add=True) updateTime = models.DateTimeField(verbose_name='修改時間',auto_now=True) description = models.TextField(verbose_name='備注',null=True,blank=True) class Meta: db_table = 'UserInfo' verbose_name = '用戶信息' verbose_name_plural = verbose_name def __str__(self): return self.username
在項目下創建序列化文件serializers.py 代碼如下
注意:注意注釋說明,fields、exclude 限定那些字段,那些字段將會被實例化或是不被實例化,如exclude = ('password',),添加用戶時,password 會被存儲為空。
# FileName : serializers.py # Author : Adil # DateTime : 2019/8/20 4:58 PM # SoftWare : PyCharm # ~/AutomatedTest/TestPlatform/serializers.py from TestPlatform.models import UserInfo from rest_framework import serializers class UserInfoSerializer(serializers.ModelSerializer): class Meta: model = UserInfo fields = '__all__' # fields 屬性設置為特殊值 '__all__',以指示應該使用模型中的所有字段。 實例化時將可以看到所有字段 # exclude = ('password',) # 注意:結尾的 ',' 逗號,去掉會序列化失敗。exclude 屬性設置為從序列化程序中排除的字段列表。 實例化時將看不到 password 字段,及password 不被序列化, # fields = ('username','password','email') # 序列化指定字段。 # exclude = ['password'] # 使用list 形式也是可以的,此時可以不要逗號。同理fields 也支持 list 形式,因為官網 就是 list形式。 # 本身ModelSerializer 它包含 .create() 和 .update() 的簡單默認實現。 所以 這里 寫不寫 下面兩個方法都行,但是在嵌套序列化 的情況下要 重寫下面兩個方法。 # def create(self, validated_data): # print("~~~~~~~~~~~~~~") # print(validated_data) # return UserInfo.objects.create(**validated_data) # # # def update(self, instance, validated_data): # # instance.name = validated_data.get('name',instance.name) # # # instance.save() # return instance
創建用戶視圖文件
# FileName : userviews.py # Author : Adil # DateTime : 2019/8/20 4:47 PM # SoftWare : PyCharm # 在應用下添加用戶中心文件夾usercenter,並創建用戶視圖文件userviews.py # TestPlatform/usercenter/userviews.py from rest_framework.views import APIView from django.http import JsonResponse from rest_framework.request import Request from TestPlatform.models import UserInfo from TestPlatform.serializers import UserInfoSerializer class AddUserView(APIView): '''添加用戶''' def post(self,request): ret = {'code':1,'msg':None,'data':None} try: username = request.data.get('username',None) print(username) user_list = UserInfo.objects.all() # 序列化實例 ul = UserInfoSerializer(user_list,many=True) # 雖然是單個實例對象,many = True 還是要加的,不加報錯。 print(ul) print(ul.data) # 根據接口提供參數 進行反序列化 ul1 = UserInfoSerializer(data=request.data) print("******") print(ul1) print(ul1.is_valid()) # 進行數據校驗,通過返回True,失敗返回False if ul1.is_valid(): print(ul1.validated_data) # 成功說明可以保存,調用 .save()保存實例到數據庫。 ul1.save() ret['msg'] = '成功!' ret['data'] = ul1.data # return JsonResponse(ul1.data) else: ret['msg'] = '失敗!' # 失敗返回失敗信息。 ret['data'] = ul1.errors except Exception as e: ret['code'] = 0 ret['msg'] = '失敗!' return JsonResponse(ret)
配置應用下urls.py文件
# FileName : urls.py # Author : Adil # DateTime : 2019/8/19 4:48 PM # SoftWare : PyCharm # TestPlatform/urls.py from django.urls import path from TestPlatform.usercenter.userviews import AddUserView urlpatterns = [ # path('add/',add) path('adduser/',AddUserView.as_view()) ]
配置項目下主urls.py文件
# AutomatedTest/urls.py from django.contrib import admin from django.urls import path,include # from django.conf.urls import url,include urlpatterns = [ path('admin/', admin.site.urls), path('auto/',include('TestPlatform.urls'))
注意:這樣配置的接口路徑為 auto/adduser/
啟動項目,
添加用戶,如圖,添加了幾個必填字段
添加重復用戶,查看提示信息
查看數據庫表
使用Serializer實現簡單的增刪改
urls.py文件
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^books/', views.BookListView.as_view()), #獲取多條數據和添加數據 url(r'^book/(\d+)/', views.BookView.as_view()), #獲取單條數據,編輯和刪除數據 ]
獲取多條數據和添加數據
serializer.py文件
from rest_framework import serializers from app01 import models class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class PublisherSerializer(serializers.Serializer): name = serializers.CharField() class BookSerializer(serializers.Serializer): title = serializers.CharField() price = serializers.DecimalField(max_digits=6, decimal_places=2) pub_date = serializers.DateTimeField() pub = PublisherSerializer(read_only=True) #GET請求時需要的數據設置為只讀,POST時可為空 authors = serializers.SerializerMethodField(read_only=True) post_pub = serializers.IntegerField(write_only=True) #POST和PUT時的數據只寫,GET時可為空 post_authors = serializers.ListField(write_only=True) def get_authors(self, obj): data_obj = AuthorSerializer(obj.authors.all(), many=True) #多個對象需要many為True return data_obj.data def create(self, validated_data): #create方法用於添加數據,validated_data校驗完的數據 book_obj = models.Book.objects.create( title=validated_data.get('title'), price=validated_data.get('price'), pub_date=validated_data.get('pub_date'), pub_id=validated_data.get('post_pub'), ) book_obj.authors.set(validated_data.get('post_authors')) return book_obj # 將book對象返回
view.py文件
from app01.serializer import BookSerializer class BookListView(APIView): def get(self, request, *args, **kwargs): all_books = models.Book.objects.all() obj = BookSerializer(all_books,many=True) return Response(obj.data) def post(self,request,*args,**kwargs): print(request.data) obj = BookSerializer(data=request.data) if obj.is_valid(): #對數據進行校驗,貌似序列化器里的多對多不會校驗 obj.save() #會去序列化器里找create()方法 return Response(obj.data) #校驗成功返回添加的數據 return Response({'error': obj.errors}) #校驗失敗返回錯誤信息
POST的數據
{ "title": "葵花寶典續集", "price": "65.50", "pub_date": "2019-07-25T07:17:09Z", "post_pub": 1, "post_authors": [ 1 ] }
返回的數據
{ "title": "葵花寶典續集", "price": "65.50", "pub_date": "2019-07-25T07:17:09Z", "pub": { "name": "沙和尚出版社" }, "authors": [ { "id": 1, "name": "沙和尚" } ] }
獲取單條數據、編輯和修改
serializer.py文件
serializer.py文件 class BookSerializer(serializers.Serializer): title = serializers.CharField() price = serializers.DecimalField(max_digits=6, decimal_places=2) pub_date = serializers.DateTimeField() pub = PublisherSerializer(read_only=True) authors = serializers.SerializerMethodField(read_only=True) post_pub = serializers.IntegerField(write_only=True) post_authors = serializers.ListField(write_only=True) def get_authors(self, obj): data_obj = AuthorSerializer(obj.authors.all(), many=True) return data_obj.data def create(self, validated_data): # validated_data校驗完的數據 book_obj = models.Book.objects.create( title=validated_data.get('title'), price=validated_data.get('price'), pub_date=validated_data.get('pub_date'), pub_id=validated_data.get('post_pub'), ) book_obj.authors.set(validated_data.get('post_authors')) return book_obj # 將book對象返回 def update(self, instance, validated_data): # 修改數據時調用update方法,instance當前要求改的數據對象 instance.title = validated_data.get('title', instance.title) instance.price = validated_data.get('price', instance.price) instance.pub_date = validated_data.get('pub_date', instance.pub_date) instance.pub_id = validated_data.get('post_pub', instance.pub_id) instance.save() instance.authors.set(validated_data.get('post_authors',instance.authors.all())) return instance #返回修改后的數據對象
view.py文件
class BookView(APIView): def get(self, request,pk, *args, **kwargs): book = models.Book.objects.filter(pk=pk).first() obj = BookSerializer(book) return Response(obj.data) def put(self,request,pk,*args,**kwargs): #修改資源 book = models.Book.objects.filter(pk=pk).first() obj = BookSerializer(data=request.data,instance=book,partial=True) #partial為True表示可以只傳修改的那部分值 if obj.is_valid(): obj.save() #保存時會調用序列化器定義好的update()方法 return Response(obj.data) #校驗成功返回修改后的對象 return Response(obj.errors) def delete(self,request,pk,*args,**kwargs): #刪除資源 book = models.Book.objects.filter(pk=pk).first() if book: book.delete() return Response({'info':'刪除成功'}) return Response({'info': '數據不存在'})
PUT的數據
"title": "葵花寶典1", "price": "63.50", "pub_date": "2019-07-25T07:17:09Z", "post_pub": 1, "post_authors": [ 1 ] } #也可只穿修改的值 { "title": "葵花寶典1" #注:只有一個元素,不要加逗號,不然校驗不通過 }
返回的數據
{ "title": "葵花寶典1", "price": "63.50", "pub_date": "2019-07-25T07:17:09Z", "pub": { "name": "沙和尚出版社" }, "authors": [ { "id": 1, "name": "沙和尚" } ] }
修改用戶信息實例
如圖修改用戶信息
view視圖文件
@action(methods=['put'],detail=False) def deluser(self,request): ''' 用戶刪除 :param request: :return: ''' print("#####") print(request) print(request.data) usr = request.data.get('username') print(usr) obj = UserInfo.objects.filter(username=usr).first() print(obj) # UserInfo.objects.update_or_create(username=obj,defaults={'nickname': usr}) # UserInfo.objects.update_or_create(username=obj, defaults={'nickname': usr}) ul1 = UserInfoSerializer(data=request.data, instance=obj) print(ul1.is_valid()) # print(ul1.data) ul1.save() print("return") print() return Response({'code': 1, 'msg': 'success', 'errors': {}}) def put(self, request, *args, **kwargs): print("#####") print(request) print(request.data) usr = request.data.get('username') print(usr) obj = UserInfo.objects.filter(username=usr).first() print(obj) # UserInfo.objects.update_or_create(username=obj,defaults={'nickname': usr}) # UserInfo.objects.update_or_create(username=obj, defaults={'nickname': usr}) ul1 = UserInfoSerializer(data=request.data,instance=obj) print(ul1.is_valid()) # print(ul1.data) ul1.save() print("return") print() return Response({'code':1,'msg':'success','errors':{}})
以上提供兩種寫法進行put請求
postman請求如下
方式1:
結果如下:
方式2:
結果如下:
先簡單介紹到這里,后續介紹一下,接口請求等相關知識。