您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關Django序列化組件Serializers該如何使用,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
我們知道前后端常用json數據結構交互, 在后端我們常想把一個對象返回給前端,但是json序列化是不能序列化對象(不過可以添加序列化參數encoder序列化原理和序列化組件差不多需要自己定義序列化類和返回的結構),所以就有了我們的序列化組件,可以自定義特定結構把對象序列化返回給前端,同時可以對前端傳入的參數進行數據校驗等功能。
models
from django.db import models # Create your models here. class Book(models.Model): id = models.IntegerField(primary_key=True) title = models.CharField(max_length=255) desc = models.CharField(max_length=255) is_deleted = models.IntegerField(choices=[(1, "刪除"), (0, "未刪除")]) author = models.CharField(max_length=255)
serializer
from rest_framework.serializers import Serializer from rest_framework import serializers class BookSerializer(Serializer): id = serializers.IntegerField() title = serializers.CharField() desc = serializers.CharField() is_deleted = serializers.ChoiceField(choices=[(1, "刪除"), (0, "未刪除")], source="get_is_deleted_display") author = serializers.CharField()
views
from app01.models import Book from app01.serializer import BookSerializer from django.http import HttpResponse, JsonResponse # Create your views here. def get_books(request): books = Book.objects.all() se = BookSerializer(books, many=True) return JsonResponse(se.data, safe=False)
結果返回:
[{"id": 1, "title": "活著", "desc": "講述一代人的人生", "is_deleted": "未刪除", "author": "余華"}]
在寫法上model和serializer的寫法非常相近,但內在邏輯model是與數據庫表的關系映射,serializer是對對象的序列化和反序列化。
常用字段類型
字段 | 字段構造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正則字段,驗證正則模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位數 decimal_palces: 小數點位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices與Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
選項參數:
名稱 | 作用 |
---|---|
max_length | 最大長度 |
min_lenght | 最小長度 |
allow_blank | 是否允許為空 |
trim_whitespace | 是否截斷空白字符 |
max_value | 最大值 |
min_value | 最小值 |
通用參數
參數名稱 | 說明 |
---|---|
read_only | 表明該字段僅用于序列化輸出,默認False |
write_only | 表明該字段僅用于反序列化輸入,默認False |
required | 表明該字段在反序列化時必須輸入,默認True |
default | 反序列化時使用的默認值 |
allow_null | 表明該字段是否允許傳入None,默認False |
validators | 該字段使用的驗證器 |
error_messages | 包含錯誤編號與錯誤信息的字典 |
label | 用于HTML展示API頁面時,顯示的字段名稱 |
help_text | 用于HTML展示API頁面時,顯示的字段幫助提示信息 |
在這里額外講一個參數source,在官方文檔中是這樣解釋的:
將用于填充字段的屬性的名稱。可以是僅接受self參數的方法,例如URLField(source='get_absolute_url'),也可以使用點分符號遍歷屬性,例如EmailField(source='user.email')。當使用點分符號序列化字段時,default如果在屬性遍歷期間任何對象不存在或為空,則可能需要提供一個值。
該值source='*'具有特殊含義,用于指示應將整個對象傳遞給該字段。這對于創建嵌套表示或對需要訪問完整對象才能確定輸出表示的字段很有用。
默認為字段名稱。
其中比較常用的用法:
1、source="get_field_name_display"如上所展示,在choice字段中可以展示選項對應的解釋,這中用法代表的是官方解釋說的可以是僅接受self參數的方法,也就是source中可以填serializer對象可以調用的方法(方法中需要傳入self),內在邏輯是這個字段會展示此方法的返回的結果。
2、source='user.email'這種用法常在ModelSerializer的子類中,其中user為User對象,此中寫法是指展示user的email屬性,常用于我們想把外鍵對象user的屬性和本對象的屬性展示在同一層級,而不是下一級。
當我們定義好序列化器時,怎么校驗傳入的字段呢?那就是is_valid方法,可以根據定義序列化器的校驗規則判斷傳入字段是否合法。
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'}) serializer.is_valid() # False serializer.errors # {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}
然后serializer.validated_data就可以獲取校驗過后的數據字典。
序列化組件校驗字段的方式常有三種:
1、首先是在字段的validators屬性, 其中傳入一個校驗方法列表如:validators=(my_validator, )其中my_validator中定義校驗規則。
def multiple_of_ten(value): if value % 10 != 0: raise serializers.ValidationError('Not a multiple of ten') class GameRecord(serializers.Serializer): score = IntegerField(validators=[multiple_of_ten])
2、最常用的是定義一個validate_field_name(self, value)的函數(其中field_name指的是字段名),函數內是具體的邏輯。
from rest_framework import serializers class BlogPostSerializer(serializers.Serializer): title = serializers.CharField(max_length=100) content = serializers.CharField() def validate_title(self, value): """ Check that the blog post is about Django. """ if 'django' not in value.lower(): raise serializers.ValidationError("Blog post is not about Django") return value
3、最后一種是定義一個validate(self, data)其中data是所有字段的鍵值對,所以這個校驗方法是對象級別的校驗。
from rest_framework import serializers class EventSerializer(serializers.Serializer): description = serializers.CharField(max_length=100) start = serializers.DateTimeField() finish = serializers.DateTimeField() def validate(self, data): """ Check that start is before finish. """ if data['start'] > data['finish']: raise serializers.ValidationError("finish must occur after start") return data
當然或許當你看到這里會問why?how? 只能說源碼是最好的答案。
在我們定義的序列化類中, 可以添加create和update方法,當我們有需求是根據反序列化后的數據在數據庫表中創建記錄或者更新某條數據,這時我們就可以在create方法和update方法中定義對應的邏輯。
class CommentSerializer(serializers.Serializer): email = serializers.EmailField() content = serializers.CharField(max_length=200) created = serializers.DateTimeField() def create(self, validated_data): return Comment.objects.create(**validated_data) def update(self, instance, validated_data): instance.email = validated_data.get('email', instance.email) instance.content = validated_data.get('content', instance.content) instance.created = validated_data.get('created', instance.created) instance.save() return instance
接下來調用serializer.save()命令便可創建一條紀錄或者更新一條記錄,其中判斷save時什么時候是創建什么時候是更新呢?關鍵在于serializer的實例化。
# .save() will create a new instance. serializer = CommentSerializer(data=data) serializer.save() # .save() will update the existing `comment` instance. serializer = CommentSerializer(comment, data=data) serializer.save()
其中當Serializer類實例化沒有傳入model對象時會調用create方法創建一條記錄, 如果Serializer類實例化時傳入了model對象就會調用update方法更新一條記錄。
有時除了反序列化的字段我們還需要其他字段怎么辦呢?我們可以在save中傳入參數名和值,可以在validated_data中根據參數名取到對應的值。
serializer.save(owner=request.user)
這樣我們就可以在validated_data.get("owner")就可以取到user對象了。
ModelSerializer和表單的ModelForm組件很相似,都極大簡化了我們的開發,可以在內部類Meta中定義對應的model,ModelSerializer就會自動生成model字段對應的Field不用我們定義。
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created']
其中fields中定義序列化的字段,如果是全部字段就寫__all__, 上述例子我們沒有定義具體的字段,ModelSerializer幫我們自動生成了 'id', 'account_name', 'users', 'created'的Field。
以下是個存在一對多和多對多字段的序列化器
serializer
from res_framework import serializers #這個類用于被實例化,多對多字段這么寫 class AuthorSerializer(serializers.Serializer): id = serializers.Charfield() name = serializers.Charfield() age = serializers.Charfield() #傳給views.py的主類 class BookSerializer(serializers.Serializer): name = serializers.Charfield() #source 可以指定字段 , id是要序列化的表名。 id = serializers.CharField(source='nid') #,source后字段用.的方式可以跨表查詢。 publish = serializer.CharField(source='publish.email') ''' 如果在models.py的book類中定義一個test方法。 def test(self): return str(self.price)+self.name ''' # 返回的結果就會有xx字段,souce不但可以指定表模型字段,還可以指定模型表方法,并且賦值給xx變量 xx = serializers.Charfield(source='test') #外鍵的實現方法: #一對多字段 #如果要通過外鍵字段返回出版社的所有信息,包括id,name,email... #obj是當前循環序列化到的數據對象 publish = serializers.SerializerMethodField() def get_publish(self,obj): return {'id‘:obj.publish.pk,'name':obj.publish.name} #多對多字段 #所有作者的詳情,也展示出來 authors = serializers.SerializermethodFiled() def get_authors(self,obj): author_list = obj.authors.all() author_ser = AuthorSerializer(author_list,many=True) return author_ser.data
views
from rest_framework.views import APIView from rest_framework.response import Response from app01 import models class BookView(APIview): def get(self,request,*args,**kwargs): #獲取所有圖書數據 response = {'status':100,'msg':'獲取成功'} book_list = models.Book.objects.all() #實例化BookSerializer類,把要序列化的數據book_list傳入 #如果要序列化querySet對象,一定要加many = True book_ser = BookSerializer(book_list,many=True) #把序列化后的數據book_ser.data 拿出來放到response字典中返回給客戶端 response['data'] = book_ser.data return Response(response)
如果使用ModelSerializer:
serializer
from app01 import models class PublishSerializer(serializers.ModelSerializer): class Meta: #固定寫法 # 指定要序列化Book表 model = models.Book #指定要序列化的字段 fields = ['nid','name'] #序列化所有字段 fileds ='__all__‘ #要排除的字段(不能與fileds連用) # exclude = ['name','price'] #深度判定 depth = 1 #如果要不按照父類的來,想要自己定義顯示的字段的話,自己定義一個,覆蓋掉父類的字段屬性。 publish = serializers.SerializerMethodField() #一對多字段 def get_publish(self,obj): return {'id‘:obj.publish.pk,'name':obj.publish.name}
這里額外解釋一下depth這個參數:在對象外鍵另一對象,另一對象又外鍵另一對象以此類推,depth的作用就是可以決定序列化時的外鍵深度。
復雜序列化器的要點在于,serializers.SerializerMethodField()和get_field_name的使用獲取自己想得到的字段值,還有source的使用,上面有講。
to_representation(self, instance):如果序列化器定義了此方法,可以改變序列化對象data的值,也就是serializer.data的值,你可以根據自己的業務場景去重新構造返回值。
def to_representation(self, instance): """Convert `username` to lowercase.""" ret = super().to_representation(instance) ret['username'] = ret['username'].lower() return ret
to_internal_value(self, data): data為未經校驗的數據字段, 此方法可以實現校驗和修改反序列化后的值,然后返回。如果不想修改反序列化后的值只是做校驗的話,完全可以使用validate方法替代。
def to_internal_value(self, value): if value == None: return 0 return value
總而言之,這兩個方法一個是用于重新構造validated_data并返回,一個用于重新構造serializer.data的值并返回。
看完上述內容,你們對Django序列化組件Serializers該如何使用有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。