内容回顾
1、前端编码格式
urlencoded:body体中 :username=lqz&password=123 django 的request.POST取出值
json格式:body体中 :{"username":"lqz","password":"123"} django 的request.POST取不出值,从request.body-->自己做反序列化
form-data:body中格式固定:数据部分和文件部分--》request.POST能取出数据,取不出文件,文件都是从request.FILES
'----------------------------789048583058585187025897\r\nContent-Disposition: form-data; name="username"\r\n\r\nlqz\r\n文件二进制
2、命令创建Django项目
django - admin startproject 项目名
3、文件对象:django中的文件对象,原生文件对象
获取文件对象
def test_body(request): print('POST--->', request.POST) # POST---> <QueryDict: {'username': ['jingzhiz']}> print('File--->', request.FILES) # File---> <MultiValueDict: {'myfile': [<InMemoryUploadedFile: 10001.jpg (image/jpeg)>]}> # print('body--->', request.body) request.body不能接收大文件,http基于TCP的流式协议 from django.core.files.uploadedfile import InMemoryUploadedFile myfile = request.FILES.get('myfile') print(myfile.size) # 286995 print(myfile.name) # 10001.jpg # print('body--->', request.body) print(type(myfile)) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> BASE_DIR = settings.BASE_DIR file_path = os.path.join(BASE_DIR, 'img')
原生文件对象 with open(f'{file_path}/{myfile.name}', 'wb') as f: print(type(f)) # <class '_io.BufferedWriter'> for line in myfile: f.write(line) return JsonResponse({'code': 100, 'msg': '请求成功'})
区别:
注意:
django中 <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> 和 <class '_io.BufferedWriter'> 两种文件对象的区别
-
InMemoryUploadedFile:
InMemoryUploadedFile
是Django中的一个类,用于处理上传的文件数据。它是从django.core.files.uploadedfile
模块中导入的。这个类代表在内存中的文件,通常是通过HTTP POST请求上传的文件。它可以处理像图片、文档等各种文件类型的数据。InMemoryUploadedFile
提供了一些方法和属性,使您可以处理上传的文件数据,比如保存到磁盘、读取、获取文件名等。 -
BufferedWriter:
_io.BufferedWriter
是Python标准库中_io
模块中的一个类,用于对二进制数据进行缓冲写入。它是Python的内置文件写入对象,用于将数据写入到文件中,可以将数据缓冲一段时间,然后一次性写入文件,以提高写入效率。通常,您可以使用Python的内置open()
函数来创建一个文件对象,并使用BufferedWriter
来写入数据。
总结区别:
InMemoryUploadedFile
是Django特有的类,用于处理上传的文件数据,而BufferedWriter
是Python标准库提供的一种用于文件写入的工具。InMemoryUploadedFile
用于处理上传的文件数据,包括保存、读取、获取文件信息等。BufferedWriter
则是用于提高文件写入效率的工具,它不直接与上传文件相关。InMemoryUploadedFile
可以包含有关上传文件的元数据和其他信息,而BufferedWriter
则专注于将数据写入文件中。
请注意,这两个类有不同的上下文和用途,因此根据您的需求,选择适合的类来处理文件操作是很重要的。文件对象有相似的属性,可以使用点方法。
5、装饰器模版
def warpper_request(func): def inner( *args, **kwargs): # 在执行被装饰函数前执行 res = func(*args, **kwargs) # 在执行被装饰函数后执行 return res return inner
6、restful规范
表正状态转移:是写前后端分离api接口的一个规范,总共十条
1.数据安全性,一般使用https,因为https比http更安全 2.数据具有api标志 3.数据就是资源,前后端交互的数据就是资源 4.响应状态码 5.不同的请求方式,返回标准不同 6.响应状态码带有错误信息 7.URL中具有版本信息,也就是多版本共存 8.url带有过滤条件(但是只针对查询)
9.资源操作有请求方式决定
10.响应中带连接
7.序列化与反序列化
反序列化:把别人的数据转换我们需要的数据类型
序列化:把我们的数据转换成别人能使用的
8、 drf,第三方模块,只能用在django,可以帮助我们快速编写符合restful规范的接口
cbv源码分析
1、执行流程
请求来了》》》路由匹配》》》如果路由匹配上,内部就会把实参request传给as_views()(request)》》》执行view函数,得到一个类的实例化对象》》》这个对象又来调用dispatch方法,先去这个类中没有找到,继续在父类view中找到dispatch方法》》》通过反射找到与请求方式相同的的方法》》》最后执行此方法,把request传到这个方法中
2、View.as_view的源码
@classonlymethod def as_view(cls, **initkwargs): # 闭包函数 def view(request, *args, **kwargs): self = cls(**initkwargs) # 类实例化得到对象:BookView的对象 # 调用对象的绑定方法 dispath---》去BookView中找dispatch--》找不到去父类---》View中的dispatch return self.dispatch(request, *args, **kwargs) # 对象的方法 return view # 执行:BookView.as_view()(request)---》本质是执行 View中as_view内部的view方法,传入了reuqest----》在执行View的dispatch方法,传入了request # 看 :View.dispatch---》源码 def dispatch(self, request, *args, **kwargs): if request.method.lower() in self.http_method_names: # 判断请求方式是否在那个固定的列表中[get, post...]---> # 反射:通过字符串 动态的 操作对象的属性或方法 # 假设是get请求---》去BookView中取出 get方法赋值给handler handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed # 执行handler加括号,传入了request # 本质是执行 get(request) return handler(request, *args, **kwargs)
总结
请求来了---》执行 视图类名.as_view()(request)---》内部执行了---》View的as_view的内部的view闭包函数---》闭包函数调用了 self.dispatch---->是BookView的,于是去了View的----》通过反射获取跟请求方式同名的方法---》然后执行,把request传入
补充
getattr:在 Python 中,该getattr()
函数是一个内置函数,用于从对象中检索属性的值,并将对象和属性名称作为参数。它通常用于动态访问对象的属性,特别是当属性名称为字符串时
getattr语法格式:
getattr(object, attribute_name, default)
object
:这是您要从中检索属性的对象。attribute_name
:这是一个字符串,指定要访问的属性的名称。default
(可选):如果该属性不存在并且提供了默认值,则将返回默认值。如果未提供且该属性不存在,AttributeError
则会引发 a 。
apiview执行流程分析
一、基于drf的apiview写接口
1.使用drf,以后都写cbv,继承的视图类都是drf提供的apiview类
2.apiview继承django中view类
3.补充:以下三个都是一个
from django.views import View
from django.views.generic import View
from django.views.generic.base import View
4.继承apiview写cbv执行跟继承view效果一样,但内部发生了一些变化
1视图类
from rest_framework.views import APIView class PublishView(APIView): def get(self, request): return JsonResponse({'code': 999})
2配置路由
path('publish/', PublishView.as_view()),
二、apiview的执行流程分析
1、apiview比继承django的view多了一些功能
1.取出csrf认证
2.包装新的request
3.执行了认证、频率、权限三大认证
4.全局异常处理:在视图类的方法中执行报错,会被异常捕获,做统一处理
2、执行流程分析
请求来了》》》匹配路由》》》路由匹配成功后,开始调用继承apiview的视图类.as_view()》》》在视图类中查找没扎到,到apiview父类中查找,apiview中的as_view调用父类view中的as_view方法,将返回值赋值给apiview中的变量view,所以view就等于父类view中的闭包函数view,而api中的as_view本质是去除csrf认证》》》调用dispatch方法,在视图类中没有
,在apiview中查找到后,dispatch包装一个全新的request赋值给原来的self.request》》》然后执行里面的三大认证》》》反射找到请求方式相同的方法,最后执行此方法,把request传到这个方法中
as_view的源码
@classmethod def as_view(cls, **initkwargs): # 调用父类的as_view得到返回值赋值给view---》django的View的as_view【看过】---》返回View的as_view的闭包函数 view view = super().as_view(**initkwargs) # 现在这个view就是原来看的View的as_view的view # 去除了csrf认证----》局部禁用csrf---》在视图函数上加 装饰器csrf_exempt # 加了装饰器的本质: 被装饰的函数=装饰器(被装饰的函数) return csrf_exempt(view) -PublishView.as_view()(request)--》执行了禁用掉csrf的View的as_view的view---》self.dispath--->APIView的dispath def dispatch(self, request, *args, **kwargs): # 1 包装了新的request对象 request = self.initialize_request(request, *args, **kwargs) # 把新的request,赋值给了 self.request # self 是 PublishView的对象 self.request = request try: # 2 执行了3大认证 self.initial(request, *args, **kwargs) ######开始### 跟之前View的dispath是一样的---》根据请求方式执行类中同名方法 ###执行视图类的方法 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 response = handler(request, *args, **kwargs) ######结束### # 执行三大认证和视图类的方法,如果出了异常,抛了错,会被捕获,统一处理 except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
装饰器本质
@auth # add=auth(add)-->以后调用add 实际上调用 auth(add)()
包装新的request
1. request.data:前端传入的数据(post,put,编码格式)》》》写到在请求体中的数据,都用
2.老request中有 request.GET 新的使用request.query_params 充当
3.其他的所有属性方法,用起来跟之前一样
三大认证
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
处理全局异常,统一处理
总结
视图类继承APIView后多了
1. 去除了csrf认证
2. 新的request
request.data
request.query_params
request.其他跟之前一样
request._request 是老的
3. 三大认证
4. 全局异常
序列化组件介绍
基于原生djagno写接口---》序列化---》自己用for循环做-->比较麻烦
借助于drf提供的序列化组件来完成快速序列化
使用步骤
1 先在配置文件中注册 :
INSTALLED_APPS = [
'rest_framework',
]
2 写一个序列化类--》新建一个py文件---》serializer.py
继承drf提供的serializers.Serializer
在类中写要序列化的字段:字段类---》跟之前学过的models.py中的字段类完全对应,但是比models多
3 在视图类中,使用序列化类
多条:serializer=UserSerializer(instance=users,many=True)
单条:serializer=UserSerializer(instance=user)
4 拿到序列化后的数据
serializer.data 可能是列表,可能是字典
5 使用drf提供的Resposne 返回
from rest_framework.response import Respons
序列化组件快速使用之序列化
1、路由
urlpatterns = [ path('users/', UserView.as_view()), path('users/<int:pk>', UserDetailView.as_view()), ]
2、视图类
from .models import User from .serializer import UserSerializer from rest_framework.response import Response class UserView(APIView): def get(self,request): users=User.objects.all() # 之前用for循环,现在用序列化类 # 传了两个参数:instance 要序列化的对象(qs,单个对象) many=True表示序列化多条,如果不写就是序列化一条 ser=UserSerializer(instance=users,many=True) # 拿到序列化后的数据 ser.data--->多条就是列表 单条字典 return Response(ser.data) class UserDetailView(APIView): def get(self,request,pk): user=User.objects.all().filter(pk=pk).first() # 传了两个参数:instance 要序列化的对象 many=True表示序列化多条 ser=UserSerializer(instance=user) return Response(ser.data)
3.序列化类
# 写序列化类 from rest_framework import serializers class UserSerializer(serializers.Serializer): # 写要序列化的字段 name = serializers.CharField() # hobby = serializers.CharField() # password=serializers.CharField() age=serializers.IntegerField()
常用字段类和参数
1、常用字段类
写序列化类的时候,写了CharField,IntegerField 跟django中models中的类似
序列化类中的和models中的一一对应,但是序列化类中多一些(
ListField
DictField
)
使用场景
{name:金鹏没,price:99,publish:{name:xx出版社,addr:南京},authors:[{},{}]}
BooleanField() | BooleanField |
---|---|
NullBooleanField() | NullBooleanField |
CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) | CharField |
EmailField(max_length=None, min_length=None, allow_blank=False) | EmailField |
RegexField(regex, max_length=None, min_length=None, allow_blank=False) | RegexField |
SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ | SlugField |
URLField(max_length=200, min_length=None, allow_blank=False) | URLField |
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" |
UUIDField |
IPAddressField(protocol=’both’, unpack_ipv4=False, **options) | IPAddressField |
IntegerField(max_value=None, min_value=None) | IntegerField |
FloatField(max_value=None, min_value=None) | FloatField |
DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 | DecimalField |
DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) | DateTimeField |
DateField(format=api_settings.DATE_FORMAT, input_formats=None) | DateField |
TimeField(format=api_settings.TIME_FORMAT, input_formats=None) | TimeField |
DurationField() | DurationField |
ChoiceField(choices) choices与Django的用法相同 | ChoiceField |
MultipleChoiceField(choices) | MultipleChoiceField |
FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) | FileField |
ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) | ImageField |
ListField(child=, min_length=None, max_length=None) | ListField |
DictField(child=) | DictField |
2、常用字段参数
字段类上,可以传参数,是做反序列化校验用的
CharField:max_length,min_lenght,allow_blank: 可以不传
IntegerField:max_value,min_value
所有字段都可以用通用的
非常重要:read_only,write_only
default,required,allow_null
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页面时,显示的字段帮助提示信息 |
序列化组件之校验
序列化组件
序列化
反序列化(没学)
反序列化校验(学了)
反序列化之校验: ser.is_valid()
1 字段自己的校验规则(字段类的属性上)
2 局部钩子(给某个字段加校验规则)
3 全局钩子
反序列化保存
ser.save()---》必须序列化类中重写 create--》自己定保存到哪个表 def create(self, validated_data): # validated_data:前端传入,校验过后的数据 user = User.objects.create(**validated_data) return user
补充
1、函数和方法
函数和方法
-函数:使用def关键字定义的函数,有几个参数,就要传几个参数,不能多,不能少-----》按位置传,按关键字传
-方法:定义在类内部,可以自动传值的函数称之为方法---》绑定给对象的方法(对象方法)---》绑定给类的方法(类 方法)
-对象方法:对象来调用,自动把对象传入,
-类也可以调用,但是类来调用,就变成了普通函数,有几个值,就要传几个值
-类方法:类来调用,自动把类传入
-对象也可以调用,内部会取到对象的类,自动传入,它也是方法
-函数和方法区别:能否自动传值
视图类
from .models import User from .serializer import UserSerializer from rest_framework.response import Response class UserView(APIView): def get(self, request): users = User.objects.all() # 之前用for循环,现在用序列化类 # 传了两个参数:instance 要序列化的对象(qs,单个对象) many=True表示序列化多条,如果不写就是序列化一条 ser = UserSerializer(instance=users, many=True) # 拿到序列化后的数据 ser.data--->多条就是列表 单条字典 return Response(ser.data) def post(self, request): # 前端提交过来的数据 request.data ser = UserSerializer(data=request.data) # 校验数据--》3层: 1 字段自己的校验规则(字段类的属性上) 2 局部钩子(给某个字段加校验规则) 3 全局钩子 if ser.is_valid(): # 保存 ser.save() # 会报错,序列化类中重写create方法 return Response({'code': 100, 'msg': '保存成功'}) else: # ser.errors 校验失败错误的数据 return Response({'code': 101, 'msg': ser.errors}) class UserDetailView(APIView): def get(self, request, pk): user = User.objects.all().filter(pk=pk).first() # 传了两个参数:instance 要序列化的对象 many=True表示序列化多条 ser = UserSerializer(instance=user) return Response(ser.data
序列化类
# 写序列化类 from rest_framework import serializers from rest_framework.exceptions import ValidationError from .models import User class UserSerializer(serializers.Serializer): # 写要序列化的字段 # 字段自己 name = serializers.CharField(max_length=8, min_length=3, required=True) hobby = serializers.CharField() password = serializers.CharField() age = serializers.IntegerField() # 局部钩子 # 写一个方法 validate_字段名,传入要校验的数据--》前端传入的 def validate_name(self, value): if value.startswith('sb'): raise ValidationError('不能以sb开头') # 如果校验失败,抛ValidationError return value # 如果校验通过,返回 value,后续继续用 # 全局钩子 # 名字和hobby不能一致 多个字段的同时校验 def validate(self, attrs): # 前端传入的所有数据,校验过后attrs 字典 name = attrs.get('name') hobby = attrs.get('hobby') if name == hobby: raise ValidationError('名字和爱好不能一样') else: return attrs # 重写create方法 def create(self, validated_data): # validated_data:前端传入,校验过后的数据 user = User.objects.create(**validated_data) return user
路由
urlpatterns = [ path('users/', UserView.as_view()), path('users/<int:pk>', UserDetailView.as_view()), ]
标签:None,self,request,day3,drf,---,序列化,view From: https://www.cnblogs.com/shanghaipudong/p/17668052.html