1. 程式人生 > 實用技巧 >Django---drf第一天

Django---drf第一天

目錄

1 序列化元件介紹

1. 序列化,序列化器會把模型物件轉換成字典,經過response以後變成json字串
2. 反序列化,把客戶端傳送過來的資料,經過request以後變成字典,序列化器可以把字典轉成模型
3. 反序列化,完成資料校驗功能

2 簡單使用

1 寫一個序列化的類,繼承Serializer
2 在類中寫要序列化的欄位,想序列化哪個欄位,就在類中寫哪個欄位
3 在檢視類中使用,匯入--》例項化得到序列化類的物件,把要序列化的物件傳入
4 序列化類的物件.data 是一個字典
5 把字典返回,如果不使用rest_framework提供的Response,就得使用JsonResponse
# ser.py
class BookSerializer(serializers.Serializer):
# id=serializers.CharField()
name=serializers.CharField()
# price=serializers.DecimalField()
price=serializers.CharField()
author=serializers.CharField()
publish=serializers.CharField() # views.py
class BookView(APIView):
def get(self,request,pk):
book=Book.objects.filter(id=pk).first()
#用一個類,毫無疑問,一定要例項化
#要序列化誰,就把誰傳過來
book_ser=BookSerializer(book) # 呼叫類的__init__
# book_ser.data 序列化物件.data就是序列化後的字典
return Response(book_ser.data) # urls.py
re_path('books/(?P<pk>\d+)', views.BookView.as_view()),

3 序列化類的欄位型別

有很多,不需要都記住
只需要記住:CharField,IntegerField,DateField。。。
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頁面時,顯示的欄位幫助提示資訊

4 序列化欄位選項

5 序列化元件修改資料

1 寫一個序列化的類,繼承Serializer
2 在類中寫要反序列化的欄位,想反序列化哪個欄位,就在類中寫哪個欄位,欄位的屬性(max_lenth......)
max_length 最大長度
min_lenght 最小長度
allow_blank 是否允許為空
trim_whitespace 是否截斷空白字元
max_value 最小值
min_value 最大值
3 在檢視類中使用,匯入--》例項化得到序列化類的物件,把要要修改的物件傳入,修改的資料傳入
boo_ser=BookSerializer(book,request.data)
boo_ser=BookSerializer(instance=book,data=request.data)
4 資料校驗 if boo_ser.is_valid()
5 如果校驗通過,就儲存
boo_ser.save() # 注意不是book.save()
6 如果不通過,邏輯自己寫 7 如果欄位的校驗規則不夠,可以寫鉤子函式(區域性和全域性)
# 區域性鉤子
def validate_price(self, data): # validate_欄位名 接收一個引數
#如果價格小於10,就校驗不通過
# print(type(data))
# print(data)
if float(data)>10:
return data
else:
#校驗失敗,拋異常
raise ValidationError('價格太低')
# 全域性鉤子
def validate(self, validate_data): # 全域性鉤子
print(validate_data)
author=validate_data.get('author')
publish=validate_data.get('publish')
if author == publish:
raise ValidationError('作者名字跟出版社一樣')
else:
return validate_data
8 可以使用欄位的author=serializers.CharField(validators=[check_author]) ,來校驗
-寫一個函式
def check_author(data):
if data.startswith('sb'):
raise ValidationError('作者名字不能以sb開頭')
else:
return data
-配置:validators=[check_author]
# models.py
class Book(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=32)
price=models.DecimalField(max_digits=5,decimal_places=2)
author=models.CharField(max_length=32)
publish=models.CharField(max_length=32) # ser.py # from rest_framework.serializers import Serializer # 就是一個類
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
# 需要繼承 Serializer def check_author(data):
if data.startswith('sb'):
raise ValidationError('作者名字不能以sb開頭')
else:
return data class BookSerializer(serializers.Serializer):
# id=serializers.CharField()
name=serializers.CharField(max_length=16,min_length=4)
# price=serializers.DecimalField()
price=serializers.CharField()
author=serializers.CharField(validators=[check_author]) # validators=[] 列表中寫函式記憶體地址
publish=serializers.CharField() def validate_price(self, data): # validate_欄位名 接收一個引數
#如果價格小於10,就校驗不通過
# print(type(data))
# print(data)
if float(data)>10:
return data
else:
#校驗失敗,拋異常
raise ValidationError('價格太低')
def validate(self, validate_data): # 全域性鉤子
print(validate_data)
author=validate_data.get('author')
publish=validate_data.get('publish')
if author == publish:
raise ValidationError('作者名字跟出版社一樣')
else:
return validate_data
def update(self, instance, validated_data):
#instance是book這個物件
#validated_data是校驗後的資料
instance.name=validated_data.get('name')
instance.price=validated_data.get('price')
instance.author=validated_data.get('author')
instance.publish=validated_data.get('publish')
instance.save() #book.save() django 的orm提供的
return instance #views.py
class BookView(APIView):
def get(self,request,pk):
book=Book.objects.filter(id=pk).first()
#用一個類,毫無疑問,一定要例項化
#要序列化誰,就把誰傳過來
book_ser=BookSerializer(book) # 呼叫類的__init__
# book_ser.data 序列化物件.data就是序列化後的字典
return Response(book_ser.data)
# return JsonResponse(book_ser.data) def put(self,request,pk):
response_msg={'status':100,'msg':'成功'}
# 找到這個物件
book = Book.objects.filter(id=pk).first()
# 得到一個序列化類的物件
# boo_ser=BookSerializer(book,request.data)
boo_ser=BookSerializer(instance=book,data=request.data) # 要資料驗證(回想form表單的驗證)
if boo_ser.is_valid(): # 返回True表示驗證通過
boo_ser.save() # 報錯
response_msg['data']=boo_ser.data
else:
response_msg['status']=101
response_msg['msg']='資料校驗失敗'
response_msg['data']=boo_ser.errors return Response(response_msg)
# urls.py
re_path('books/(?P<pk>\d+)', views.BookView.as_view()),

6 read_only和write_only

read_only	表明該欄位僅用於序列化輸出,預設False,如果設定成True,postman中可以看到該欄位,修改時,不需要傳該欄位
write_only 表明該欄位僅用於反序列化輸入,預設False,如果設定成True,postman中看不到該欄位,修改時,該欄位需要傳 # 以下的瞭解
required 表明該欄位在反序列化時必須輸入,預設True
default 反序列化時使用的預設值
allow_null 表明該欄位是否允許傳入None,預設False
validators 該欄位使用的驗證器
error_messages 包含錯誤編號與錯誤資訊的字典

7查詢所有

# views.py
class BooksView(APIView):
def get(self,request):
response_msg = {'status': 100, 'msg': '成功'}
books=Book.objects.all()
book_ser=BookSerializer(books,many=True) #序列化多條,如果序列化一條,不需要寫
response_msg['data']=book_ser.data
return Response(response_msg) #urls.py
path('books/', views.BooksView.as_view()),

8 新增資料

# views.py
class BooksView(APIView): # 新增
def post(self,request):
response_msg = {'status': 100, 'msg': '成功'}
#修改才有instance,新增沒有instance,只有data
book_ser = BookSerializer(data=request.data)
# book_ser = BookSerializer(request.data) # 這個按位置傳request.data會給instance,就報錯了
# 校驗欄位
if book_ser.is_valid():
book_ser.save()
response_msg['data']=book_ser.data
else:
response_msg['status']=102
response_msg['msg']='資料校驗失敗'
response_msg['data']=book_ser.errors
return Response(response_msg)
#ser.py 序列化類重寫create方法
def create(self, validated_data):
instance=Book.objects.create(**validated_data)
return instance
# urls.py
path('books/', views.BooksView.as_view()),

9 刪除一個資料

# views.py
class BookView(APIView):
def delete(self,request,pk):
ret=Book.objects.filter(pk=pk).delete()
return Response({'status':100,'msg':'刪除成功'})
# urls.py
re_path('books/(?P<pk>\d+)', views.BookView.as_view()),

10 模型類序列化器

class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book # 對應上models.py中的模型
fields='__all__'
# fields=('name','price','id','author') # 只序列化指定的欄位
# exclude=('name',) #跟fields不能都寫,寫誰,就表示排除誰
# read_only_fields=('price',)
# write_only_fields=('id',) #棄用了,使用extra_kwargs
extra_kwargs = { # 類似於這種形式name=serializers.CharField(max_length=16,min_length=4)
'price': {'write_only': True},
} # 其他使用一模一樣
#不需要重寫create和updata方法了

11 原始碼分析

many=True的實際用途

# 序列化多條,需要傳many=True
#
book_ser=BookModelSerializer(books,many=True)
book_one_ser=BookModelSerializer(book)
print(type(book_ser))
#<class 'rest_framework.serializers.ListSerializer'>
print(type(book_one_ser))
#<class 'app01.ser.BookModelSerializer'> # 物件的生成--》先呼叫類的__new__方法,生成空物件
# 物件=類名(name=lqz),觸發類的__init__()
# 類的__new__方法控制物件的生成 def __new__(cls, *args, **kwargs):
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
# 沒有傳many=True,走下面,正常的物件例項化
return super().__new__(cls, *args, **kwargs)

Serializer高階用法

# source的使用
1 可以改欄位名字 xxx=serializers.CharField(source='title')
2 可以.跨表publish=serializers.CharField(source='publish.email')
3 可以執行方法pub_date=serializers.CharField(source='test') test是Book表模型中的方法 # SerializerMethodField()的使用
1 它需要有個配套方法,方法名叫get_欄位名,返回值就是要顯示的東西
authors=serializers.SerializerMethodField() #它需要有個配套方法,方法名叫get_欄位名,返回值就是要顯示的東西
def get_authors(self,instance):
# book物件
authors=instance.authors.all() # 取出所有作者
ll=[]
for author in authors:
ll.append({'name':author.name,'age':author.age})
return ll

補充

1 如果有這個錯(把rest_framework在app中註冊一下)

2補充自己封裝Respons物件

class MyResponse():
def __init__(self):
self.status=100
self.msg='成功'
@property
def get_dict(self):
return self.__dict__ if __name__ == '__main__':
res=MyResponse()
res.status=101
res.msg='查詢失敗'
# res.data={'name':'lqz'}
print(res.get_dict)

3 你在實際開發中碰到的問題及如何解決的

write_only_fields 不能使用了,使用extra_kwargs解決了
extra_kwargs = {
'id': {'write_only': True},
}

作業:

1 圖書的5個介面寫完(使用序列化元件)

2 嘗試修改一下返回的欄位名字