DRF之APIView
目录
APIView执行流程
基于APIView+JsonResponse编写接口
原来基于django原生的view编写接口
drf提供给咱们的一个类,以后使用drf写视图类,都是集成这个类及其子类,APIView本身就是集成了Django原生的View
代码展示:
from rest_framework.views import APIView
from .models import Book
from django.http import JsonResponse
class BookView(APIView):
def get(self, request):
# 拿到所有的数据
books = Book.objects.all()
# 缺点是还要自己for循环放到列表
book_list = []
for book in books:
book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
# 序列化不支持列表,需要填写参数
return JsonResponse(book_list, safe=False)
基于APIView+Response写接口
from rest_framework.views import APIView
from .models import Book
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
# 拿到所有的数据
books = Book.objects.all()
book_list = []
for book in books:
book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
# 相对于JsonResponse来说,不需要再写参数,列表同样可以序列化
return Response(book_list)
APIView的执行流程
"""
首先复习对象名字的查找顺序,先在对象自己的内部名称空间,然后到产生对象的类,在到产生对象的类的父类中查找,每一次查找名字都是按照这样的顺序去找
"""
路由中写的: path('books/', views.BookView.as_view()),---》请求来了,执行views.BookView.as_view()()----->现在的as_view是APIView的as_view,因为我们自己写的类没有这个as_view这个方法,所以要从父类中寻找,现在我们的父类是APIView
class APIView(View):
# 这里我们可以看到APIView其实继承的还是django原生的View
@classmethod # 这句话标识是绑定给类的方法,那么调用这个as_view会直接将类传入,我们是自己写的类在路由层调用了该方法,所以会将我们自己写的类作为第一个参数传入,也就是参数的cls
def as_view(cls, **initkwargs):
# APIView的as_view方法:view还是原来的view,但是以后再也没有csrf认证了
view = super().as_view(**initkwargs)
# 上面这句话表示子类调用父类的方法,也就是调用View类的as_view方法,然后拿到了里面的闭包函数view
view.cls = cls
view.initkwargs = initkwargs
# csrf_exempt是装饰器,这样写其实就是装饰器语法糖作用在view这个函数上直接将函数作为参数传入,那么执行view这个函数就全程不会校验scrf了
return csrf_exempt(view)
# 路由匹配成功,执行csrf_exempt(view)(requets)--->在执行view这个函数也就是在View类中的as_view中的闭包函数view---》这个函数会返回执行self.dispatch---->self是视图类的对象---->BookView---->然后对象点dispatch方法,首先从对象自己找然后再找产生对象的类也就是BookView都没有再从父类里面找也就是APIView里面的dispatch方法,找到了
def dispatch(self, request, *args, **kwargs):
# request是django原生的request,老的request
# 把老的request包装成了新的request,这个是drf提供的Request类的对象
request = self.initialize_request(request, *args, **kwargs)
# 到此以后,这个request就是新的了,老的request在哪?
# request._request 这是老的
# 把新的request放到了self对象【BookView的对象】
self.request = request
try:
# 执行了三大认证【认证,频率,权限】,使用新的request,不读
self.initial(request, *args, **kwargs)
# 跟之前一毛一样
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 把新的request传入了,视图类的方法中get的request也是新的
response = handler(request, *args, **kwargs)
except Exception as exc:
# 在执行3大认证和视图类中方法的过程中,如果出了异常,都能捕获到---》全局异常捕获
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
总结:APIView的执行流程
1.去除了所有的csrf
2.包装了新的request,以后在视图类中的request是新的request,Request类的对象,不是原生的了
-原生的在新的request._request
3.在执行视图类的方法之前,执行了3大认证
4.如果在3大认证或者视图函数方法执行过程中出了错,就会有异常捕获---》全局异常捕获
5.以后视图类方法中的request都是新的了
Request对象源码分析
新的Request----》区别于老的
老的:django.core.handlers.wsgi.WSGIRequest
新的:from rest_framework.request import Request
新的request._request 就是老的
Request源码
-方法 __getattr__
-在视图类的方法中,执行request.method,新的request是没有method方法的,就出发了新的Request的__getattr__方法执行
def __getattr__(self, attr):
try:
# 从老的request中反射出 要取得属性
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
所以我们使用新的request点method的时候其实拿到的是老的request.method的结果
request.data---》是个方法,包装成了数据属性
--以后无论post、put等放在body中提交的数据,都从request.data中取,取出来的就是字段
--无论是哪种编码格式
request.query_params---》这是个方法,包装成了数据属性
-get请求携带的参数,以后从这里面取
-query_params:查询参数--->restful规范请求地址中带查询参数
-request.FILES--->这是个方法,包装成了数据属性
-前端提交过来的文件,从这里取
# Request类总结
1.新的request用起来,跟之前一模一样,因为新的取不到,会自动出发__getattr__取老的对应的方法
2.request.data 无论什么编码,什么请求方法,只要是body中的数据,就从这里取,字典
3.request.query_params 就是原来的request._request.GET
4.上传的文件从request.FILES中取
序列化器介绍和快速使用
因为我们在写接口时,需要序列化和反序列化,而且反序列化的过程中要做数据校验---》drf直接提供了固定的写法,只要按照固定写法使用,就能完成上面的三个需求
# 提供了两个类 Serializer ModelSerializer
-以后只需要写自己的类,集成drf提供的序列化类,使用其中的某些方法,就能完成上面的操作
# 使用APIView+序列化类+Response完成接口的编写
序列化类基本使用,序列化多条
Serializer.py--BookSerializer类
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 序列化某些字段,这里要写序列化的字段
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
views.py-->BookView类
from rest_framework.views import APIView
from .models import Book
from rest_framework.response import Response
from .Serializer import BookSerializer
class BookView(APIView):
def get(self, request):
print(request.method) # GET
print(request._request.method) # GET
print(self.request._request.method) # GET
# 拿到所有的数据
books = Book.objects.all()
# 使用序列化类来完成序列化
# instance是要序列化的数据boos queryset对象
# many=True 只要是queryset对象要穿many=True,如果是单个对象就不用传
ser = BookSerializer(instance=books,many=True)
return Response(ser.data) # 无聊是列表还是字典都可以序列化
序列化单条
序列化类没动
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 序列化某些字段,这里要写序列化的字段
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
视图类重新写一个新的
from rest_framework.views import APIView
from .models import Book
from rest_framework.response import Response
from .Serializer import BookSerializer
class BooksView(APIView):
def get(self, request, *args, **kwargs):
book = Book.objects.filter(pk=kwargs.get('pk')).first()
# 序列化,单条不用写many=True
ser = BookSerializer(instance=book)
return Response(ser.data)
url添加新的路由
urlpatterns = [
path('book/<int:pk>/', views.BooksView.as_view()),
]
反序列化
反序列化的新增
序列化类写一个create方法
def create(self, validated_data):
# 保存的逻辑
# validated_date是校验过后的数据
# 保存到数据库
book = Book.objects.create(**validated_data)
# 一定要返回新增的对象
return book
视图类
def post(self, request):
ser = BookSerializer(data=request.data) # 把前端传入的要保存的数据吗,给data参数
# 校验数据
if ser.is_valid():
# 保存需要自己写,要在序列化类BookSerializer中写一个create方法
ser.save() # 调用ser.save方法自动出发咱们写的create保存数据
return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
return Response({'code': 101, 'msg': ser.errors})
序列化的修改
序列化类写一个修改的方法
def update(self, instance, validated_data):
# instance要修改的对象,也就是我们数据库中原来的orm对象
# validated_data前端传过来校验后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save() # orm的单个对象,修改了单个对象的属性,只要对象调用了save方法,就可以把修改的保存到数据库中
return instance # 把修改后的对象返回出去
视图类
def put(self, request, **kwargs):
# 获取要修改的数据对象
book = Book.objects.filter(pk=kwargs.get('pk')).first()
# 把要修改的数据对象和前端的传来的数据都传给序列化类
ser = BookSerializer(data=request.data, instance=book)
if ser.is_valid():
ser.save() # 调用save方法自动调用我们写的update方法
return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
return Response({'code': 101, 'msg': ser.errors})
删除单条
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '删除成功'})
反序列化的校验
序列化反序列化,数据校验功能----》类比forms组件
局部钩子和全局钩子
from rest_framework import serializers
from .models import Book
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.Serializer):
# 序列化某些字段,这里要写序列化的字段
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
# 保存的逻辑
# validated_date是校验过后的数据
# 保存到数据库
book = Book.objects.create(**validated_data)
# 一定要返回新增的对象
return book
def update(self, instance, validated_data):
# instance要修改的对象,也就是我们数据库中原来的orm对象
# validated_data前端传过来校验后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save() # orm的单个对象,修改了单个对象的属性,只要对象调用了save方法,就可以把修改的保存到数据库中
return instance # 把修改后的对象返回出去
# 局部钩子
def validate_name(self, name):
# 校验name是否合法
if name.startswith('sb'):
# 校验不通过,抛异常
raise ValidationError('不能以sb开头')
else:
return name
# 全局钩子
def validate(self, attrs):
# attrs就是前端传来的数据
if attrs.get('name') == attrs.get('publish'):
raise ValidationError('书名跟出版社名字不能一致')
else:
return attrs
序列化类常用的字段和字段参数
序列化类---》字段类 CharField,除此之外还有不少
序列化类---》字段类,字段类上,传属性的,序列化类上,也可以写属性
类似于:【models.CharField(max_length=32)】
常用字段类
#1 BooleanField BooleanField()
#2 NullBooleanField NullBooleanField()
#3 CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
#4 EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
#5 RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
#6 SlugField SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
#7 URLField URLField(max_length=200, min_length=None, allow_blank=False)
#8 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"
#9 IPAddressField IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
#10 IntegerField IntegerField(max_value=None, min_value=None)
#11 FloatField FloatField(max_value=None, min_value=None)
#12 DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
#13 DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
#14 DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
#15 TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
#16 DurationField DurationField()
#17 ChoiceField ChoiceField(choices) choices与Django的用法相同
#18 MultipleChoiceField MultipleChoiceField(choices)
#19 FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
#20 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=)
#记住的:CharField IntegerField DecimalField DateTimeField BooleanFieldListFieldDictField
常用字段参数
选项参数:
# CharField及其子类的(EmailField)---》反序列化的校验,字段自己的规则
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
# IntegerField
max_value 最大值
min_value 最小值
# 所有字段类都有的
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用验证器
----看一眼忘掉-----
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
# 重点:
read_only 表明该字段仅用于序列化输出,默认False
srite_only 表明该字段仅用于反序列化输入,默认False
# 反序列化校验执行流程
-1.先执行字段自己的校验规则---》最大长度,最小长度,是否为空,是否必填,最小数据。。。
-2 validators=[方法,] ----》单独给这个字段加校验规则
name=serializers.CharField(validators=[方法,])
-3 局部钩子校验规则
-4 全部钩子校验规则
序列化高级用法之source
# 创建关联表
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) # 留住,还有很多
authors = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11)
# 迁移,录入数据
序列化定制字段名字
# 重点:source可以指定序列化字段的名字
-自有字段,直接写字段名字
-name_real = serializers.CharField(max_length=8, source='name')
-关联字段,一对多的关联,直接点
-publish = serializers.CharField(source='publish.name')
-多对多,搞不了,source不能用
-authors=serializers.CharField(source='authors.all')
# 关联字段,一对多的关联,直接点,会直接显示名字
publish = serializers.CharField(source='publish.name')
#多对多,搞不了,source不能用,显示不出来
authors=serializers.CharField(source='authors.all')
序列化高级用法之定制字段的两种方式
SerializerMethodField定制
# 定制关联字段的显示形式
-一对多,显示字典
-多对多,显示列表套字典
代码展示:
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
new_name = serializers.CharField(source='name')
price = serializers.CharField()
# 定制返回格式---》方式一
publish_detail = serializers.SerializerMethodField()
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'addr': obj.publish.addr}
author_list = serializers.SerializerMethodField()
def get_author_list(self, obj):
author_list = obj.authors.all()
return [{'name': author.name, 'phone': author.phone} for author in author_list]
在模型表中定制
# 模型类中:
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
# 外键字段
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
@property # 利用伪装,可以直接点,返回的还是一样的
def publish_detail(self):
return {'name': self.publish.name, 'addr': self.publish.addr}
@property
def authors_list(self):
author_list = self.authors.all()
return [{'name': author.name, 'phone': author.phone} for author in author_list]
# 序列化类
class BookSerializer(serializers.Serializer):
new_name = serializers.CharField(source='name')
price = serializers.CharField()
# 这两个就相当于普通的字段直接Book对象序列化时点方法就可以点出来
publish_detail = serializers.DictField()
authors_list = serializers.ListField()
多表关联序列化保存
新增图书接口
-前端传入的数据格式:{name:红楼梦,price:19,publish:1,authors:[1,2]}
"""注意字段要跟反序列类中的字段名是一致的"""
# 视图类
class BookView(APIView):
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '新增成功'})
else:
return Response({'code': 101, 'msg': ser.errors})
# 序列化类
class BookSerializer(serializers.Serializer):
# name和price 既用来序列化,又用来反序列化 即写又读 ,不用加read_only,write_only
name = serializers.CharField(max_length=8)
price = serializers.CharField()
# 只用来做序列化 只读 read_only
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 只用来做反序列化 只写 write_only
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
# 新增要重写create方法
def create(self, validated_data):
# validated_data 校验过后的数据,{name:红楼梦,price:19,publish:1,authors:[1,2]}
# 新增一本图书
book = Book.objects.create(name=validated_data.get('name'), price=validated_data.get('price'),
publish_id=validated_data.get('publish'))
# 作者也要关联上
# book.authors add remove set clear....
book.authors.add(*validated_data.get('authors'))
# book.authors.add(1,2)
return book
修改图书接口
# 新增图书接口
-前端传入的数据格式:{name:红楼梦,price:19,publish:1,authors:[1,2]}
###视图类
class BookDetailView(APIView):
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功'})
else:
return Response({'code': 101, 'msg': ser.errors})
# 序列化类
#### 反序列化的多表关联的保存
class BookSerializer(serializers.Serializer):
# name和price 既用来序列化,又用来反序列化 即写又读 ,不用加read_only,write_only
name = serializers.CharField(max_length=8)
price = serializers.CharField()
# 只用来做反序列化 只写 write_only
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
# 修改要重写update
def update(self, instance, validated_data):
# validated_data 校验过后的数据,{name:红楼梦,price:19,publish:1,authors:[1,2]}
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish_id = validated_data.get('publish')
# 先清空,再add
authors = validated_data.get('authors')
instance.authors.clear()
instance.authors.add(*authors)
instance.save()
return instance
反序列化字段校验其他
# 4层
-1 字段自己的:举例:name = serializers.CharField(max_length=8, error_messages={'max_length': '太长了'})
-2 validators=[方法,] 忽略掉
-3 局部钩子
-4 全局钩子
ModelSerializer使用
# MOdelserializer 集成自Serializer,帮咱们完成了很多操作
-模型表强关联
-大部分请求,不用写create和update了
### ModelSerializer的使用
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book # 跟book表建立了关系 序列化类和表模型类
# fields = '__all__' # 序列化所有Book中的字段 id name price publish authors
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors'] # 序列化所有Book中的name和price字段字段
# 定制name反序列化时,最长不能超过8 给字段类加属性---方式一
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
# 如果Meta写了__all__ ,就相当于,复制了表模型中的所有字段,放在了这里,做了个映射
# name = serializers.CharField(max_length=32)
# price = serializers.CharField(max_length=32)
# 定制name反序列化时,最长不能超过8 给字段类加属性---方式二,重写name字段
# name = serializers.CharField(max_length=8)
# 同理,所有的read_only和wirte_only都可以通过重写或使用extra_kwargs传入
# 终极,把这个序列化类写成跟之前一模一样项目
# publish_detail = serializers.SerializerMethodField(read_only=True)
# def get_publish_detail(self, obj):
# return {'name': obj.publish.name, 'addr': obj.publish.addr}
# author_list = serializers.SerializerMethodField(read_only=True)
# def get_author_list(self, obj):
# l = []
# for author in obj.authors.all():
# l.append({'name': author.name, 'phone': author.phone})
# return l
# 局部钩子和全局钩子跟之前完全一样
def validate_name(self, name):
if name.startswith('sb'):
raise ValidationError('不能sb')
else:
return name
ModelSerializer:继承自Serializer
class BookSerializer(ModelSerializer):
# 如果字段是映射过来的,也会把字段属性(反序列化校验规则)映射过来,有可能会校验失败,不能写入
# 可以重写这个字段,不加任何规则,取消掉它
name = serializer.CharField()
class Meta:
model = Book # 跟表进行关联
fields = [要使用到的字段名,可以是表里面的,也可以是关联表里面的]
extra_kwargs = {} # 给字段类增加属性:read_only write_only用的多
# book表里面没有的字段,我们就要在序列化类里面再写一下
gender = serializer.CharField()
addr = serializer.CharField()
反序列化的字段,一定跟表模型的字段是对应的么,不一定
反序列化类校验部分源码解析(了解)
# 反序列化校验,什么时候,开始执行校验
-视图类中的ser.is_valid(),就会执行校验,校验通过,返回True,不通过返回False
# 入口:ser.in_valid()是序列化类的对象,假设序列化类是BookSerializer---》is_valid---》找不到,找到父类BaseSerializer中有:【raise_exception:先注意】
def is_valid(self, *, raise_exception=False):
if not hasattr(self, '_validated_data'):
try:
# self序列化类的对象,属性中没有_validated_data,一定会走这一条,添加一个方法,所以找到这个方法
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
# self._validated_data = self.run_validation(self.initial_data)核心---》self序列化类的对象
-切记一定不要按住ctrl键点击
-真正的执行顺序是,从下往上找,找不到,再往上
-最终从Serializer类中找到了run_validation,而不是Field中的run_validation
def run_validation(self, data=empty):
"""
这个函数的注释:
我们重写默认的run_validation',因为由验证器和".validate() '方法执行的验证应该使 用'non_fields_error'键强制放入错误字典。
"""
# 字段自己的,validates方法
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# 局部钩子
value = self.to_internal_value(data)
try:
self.run_validators(value)
# 全局钩子
value = self.validate(value)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
# 局部钩子self.to_internal_value(data),self还是BookSerializer的对象,从根上找,还是在Serializer
def to_internal_value(self, data):
# 属性
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
# fields写在序列化类中一个个字段类的对象
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
# 在执行BookSerializer类中的validate_name方法,传入了要校验的数据
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
# 了解self._writable_fields,其实就是做了一个判断,字段类的属性是不是只读的,因为不是只读,代表就是只写或者写和读都有,这样的字段是反序列化使用的字段
def _writable_fields(self):
for field in self.fields.values():
if not field.read_only:
yield field
断言
# 源码中大量使用try和断言
# 关键字assert,就是断定你是xx,如果不是就抛异常
name = 'lqz'
# if name == 'lqz':
# print('对了')
# else:
# # print('错了')
# raise Exception('名字不为lqz,不能继续走了')
assert name == 'lqz' # 断定是,如果不是,就抛异常
print('后续代码')
drf之请求
Request能够解析的前端传入的编码格式
# 需求是该接口只能接受json格式,不能接受其他格式
# 方式一:在集成自APIView及其子类的视图类中配置(局部配置)
# 总共有三个:from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser,]
# 方式二:在配置文件中配置(影响所有,全局配置)
-django有套默认配置,每个项目有个配置
-drf有套默认配置,每个项目也有个配置---》就在django的配置文件中
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
# 'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
# 方式三:全局配了1个,某个视图类想要3个,怎么配?
-只需要在视图类,配置3个即可
-因为:先从视图类自身找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置找
Request类有哪些属性和方法
request.data post,put等请求放在请求体中的
__getattr__ request点不存在的时候会出发老的request的方法
query_params 老的request.GET
drf之响应
Response能够响应的编码格式
# drf 是django的一个app,所以要注册
# drf的响应,如果使用浏览器和postman访问同一个接口,返回格式是不一样的
-drf做了判断,如果是浏览器,好看一些,如果是postman只要json数据
# 方式一:在视图类中写(局部配置)
-两个响应类---》找---》def的配置文件中找--》两个类
-from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,]
# 方式二:在项目配置文件中写(全局配置)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 方式三:使用顺序(一般就用内置的即可)
优先使用视图类中的配置,其次使用项目配置文件中的配置,最后使用内置的
Response的源代码属性或方法
# drf的Respnose 源码分析
from rest_framework.response import Response、
视图类的方法返回时,return Response,走他的__init__中可以传什么参数
def __init__(self, data=None,
status=None,
template_name=None,
headers=None,
exception=False,
content_type=None):
-data:就是我们之前写的ser.data,返回给前端的数据,可以是字典或列表,字符串---》序列化后返回给前端---》前端在响应体中看到的就是这个
-status:http响应的状态码,默认是200,可以修改
-drf在status包下,把所有http响应状态码都写了一遍,常量
-from rest_framework.status import HTTP_200_OK
-Response('dddd',status=status.HTTP_200_OK)
-template_name:了解即可,修改响应模板的样子,BrowsableAPIRenderer定死的样子,后期公司可以自己定制
-headers:响应头,http响应的响应头
-考你,原生djagno,如何像响应头中加东西
# 四件套 render,redirect,HttpResponse,JsonResponse
obj = HttpResponse('dddd')
obj['xxc'] = 'yyc'
return obj
-content_type :响应编码格式,一般不动
# 重点data,status,headers
视图组件介绍及两个视图基类
# drf视图,视图类,学过的APIView,def的基类,def提供的最顶层的楼
# APIView跟之前的view区别
-传入到视图方法中的是REST frameword的Request对象,而不是Django的HttpRequest对象
-视图方法可以返回REST framework的Response对象
-任何APIException异常都会被捕获到,并且处理成合适的响应信息
-在进行dispatch()分发前,会对请求进行身份认证,权限检查,流量控制
# 两个视图基类
APIView
类属性:
renderer_classes # 响应格式
parser_classes # 能够解析的请求格式
authentication_classes # 认证类
thorttle_classes #频率类
permission_classes # 权限类
基于APIView+ModelSerializer+Response写5个接口
APIView+ModelSerializer+Resposne写5个接口
视图类
from .models import Book
from .serializer import BookSerializer
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
ser = BookSerializer(instance=books, many=True)
return Response(ser.data)
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
# 咱们现在只有ser序列化类的对象,但是咱们想要,新增的对象---》序列化成字典---》大前提,序列化类中的create方法一定要返回新增的对象
return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDetailView(APIView):
def get(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books)
return Response(ser.data)
def put(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '删除成功'})
序列化类
### ModelSerializer的使用
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
路由
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
基于GenericAPIView
视图层
"""
GenericAPIView的属性:
1 queryset:要序列化或反序列化的表模型数据
2 serializer_class: 使用的序列化类
3 lookup_field 查询单条的路由分组分出来的字段名
4 filter_backends 过滤类的配置
5 pangintion_class 分页类的配置
方法:
get_queryset 获取要序列化的对象
get_object 获取单个对象
get_serializer 获取序列化类
"""
from rest_framework.generics import GenericAPIView
class BooksView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = Bookserializer
def get(self, request):
obj = self.get_queryset()
ser = self.get_serializer(instance=obj,many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '新增成功'})
class BookView(GenericAPIView):
queryset = Book
serializer_class = Bookserializer
def get(self, request, pk):
# 这里参数必须是pk,这样就可以查询到了lookup_field = 'pk',因为这个参数问题
book = self.get_object()
# 序列化
ser = Bookserializer(instance=book)
return Response(ser.data)
# 修改一个
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = Bookserializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功'})
return Response({'code': 101, 'msg': '修改失败', 'result': ser.errors})
基于GenericAPIView+5个视图扩展类
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
CreateModelMixin: 创建,create方法
UpdateModelMixin:更新,update方法
DestroyModelMixin:删除,destroy方法
RetrieveModelMixin:查询单条,retrive方法
ListModelMixin:查询所有,list方法