1.http请求协议

代码很枯燥,结果和奇妙。

1.cbv
django.vuews import View
classs LoginView(View):
def get(self,requset):
pass
2.classmethod $ classonlymethod
3.getattr hasattr setattr
4.self定位
- 始终代表调用者本身
5.http请求协议:就是约定成俗的规范,解析数据的规范
6.form enctype
解析参数的格式
7. javascript object {name: "alex"} ===>json转换的方式
7.1 data:Json.stringify({name: "alex", age: 18}) ==>json.dumps(data)
JSON.parse(data) ===> json.loads()

今日详情:

1. djaong-restframework

​ 1.1 ApiVIew

urlpatterns = [
re_path('^course/$', views.CourseView.as_view()),
]
url_mapping = {
"login": "LoginView"
}
第一步:从as_view向里看
rest-framework如何对django的view进行扩展的呢

​ 1.2 解析器组件

​ 1.3 序列化组件

​ 1.4 认证组件

​ 1.5 权限组件

​ 1.6 频率组件

​ 1.7 url控制器组件

​ 1.8 分页组件

​ 1.9 响应器组件

今日内容总结:

  • 知识点复习总结

    • 什么是编程

      数据结构+算法

    • 什么是rest

      https://www.jd.com #通过url拿到数据
      2.1原始url
      127.0.0.1:8001/books/id/
      127.0.0.1:8001/books/?name=""
      127.0.0.1:8001/books/delet/id/
      这种url方式使得接口看起来多而且杂,维护不方便
      url用来唯一定位资源,用http请求方式来区分用户对数据的操作方式
      2.2rest url
      1.url设置规范
      GET:127.0.0.1:8001/books/ # 获取所有数据
      GET:127.0.0.1:8001/books/id/ # 获取单挑数据
      POST:127.0.0.1:8001/books/ # 增加数据
      DELETE:127.0.0.1:8001/books/id/ # 删除数据
      UPDATE:127.0.0.1:8001/books/id/ # 更改数据
      2.数据响应规范
      GET:127.0.0.1:8001/books/ # 获取所有数据 返回[{}, ,]
      GET:127.0.0.1:8001/books/id/ # 获取单挑数据 返回{}单条数据
      POST:127.0.0.1:8001/books/ # 增加数据 返回{}添加成功
      DELETE:127.0.0.1:8001/books/id/ # 删除数据 返回‘’返回空
      put/UPDATE:127.0.0.1:8001/books/id/ # 更改数据 返回更新后的完整数据
      3.错误处理
      {"error":"message"}
    • cbv

    • classmethod & classonly method

    • getattr hasattr setattr

      动态对对象的属性进行操作

    • self定位

      始终定位的是自己

    • http请求数据的协议

      后端用什么方式来解析请求的数据

    • from表单的enctype里面的三种请求协议

      urlencoded, multi-formdata, text/plain

    • JavaScript object 序列化成json

      object =>json(json.stringify) json==>object(JSON.parse())




class LoginView(ApiView):
def post(self,request):
data = request.data #新的request对象
return class ApiVIew(View): @classmethod
def as_view(self, request):
pass
super(ApiView,self).as_view(**initkwargs)
def dispatch():
request = self.initialize_request(request, *args, **kwargs)
self.request = request
parser_context = self.get_parser_context(request) return Request(
request, # 原生reqeust
parsers=self.get_parsers(), # get_parsers()
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
) ApiView.py中的
def get_parsers(self):
"""
Instantiates and returns the list of parsers that this view can use.
"""
return [parser() for parser in self.parser_classes]
from rest_framework.request import Request
data = request.data #新的request对象
从reqeust中.出来的,所以其Request中找这个属性

3.解析器源码流程:

__getattr__在属性未找到的时候
第一步:执行as_view()
第二步:自己写的里面没有as_view()函数去父类中找
第三部:执行view中的as_view()方法,返回view函数
第四步:url和驶入函数之间的绑定关系建立完毕{“login”: view}等待用户请求
第五步:接收到用户请求:login,到建立好的关系里面执行对应的视图函数:view(request)
第六步:视图函数的执行结果是什么就返回给客户,self.dispatch(),self.dispatch()的执行结果
第七步:此时的self代表的是LoginView的实例对象
第八步:开始找dispatch方法,self里面没有,LoginVIew里面也咩有,在ApiView中
第九步:开始执行apiview中的dispatch方法
第十步:在最后找到http方法(get,post,put,delete),根据请求的类型查找(reqeust.method.lower())
第十一步:执行第十步找到的方法,开始执行找到的方法self.get()代表的是LoginView的实例化对象
11.1 假设接受到的时候POST请求,执行reuqest。data
11.2 分析结果,所有的解析工作都是在request。data里面实现的,且data是一个方法(被属性化之后的)
11.3 拿取data
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
11.4 执行_load_data_and_files()
11.5 parser = self.negotiator.select_parser(self, self.parsers)
11.5.1parsed = parser.parse(stream, media_type, self.parser_context)
11.5.2 self.get_parses()
return [parser() for parser in self.parser_classes]
11.5.3 parser_classes = api_settings.DEFAULT_PARSER_CLASSES
11.5.4 api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
11.5.6 APISettings是一个类
11.5.7 找不到parser_classes = api_settings.DEFAULT_PARSER_CLASSES
的时候就去__getattr__里面找
11.5.8 __getattr__里面有这么一句话 val = self.user_settings[attr]
@property
def user_settings(self):
if not hasattr(self, '_user_settings'):
self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
return self._user_settings
11.5.9 首先找自己的settiongs,之后找rest_framework的settings 11.6 得到self._data = parsed.data
11.7 DRF将self.date = self._data
11.8 reqeust.data
第十二部:在loginView里面找到对应的方法,执行该方法,最后返回给用户
  • DRF的所有功能都是在as_view()和dispatch()里面重写的
  • 而解析器组件在dispatch方法里面重写了,具体实在重新封装的Request对象中
class ParseJson():

	pass
class ParseForm():
data = request.body.decode('utf-8')
data.split("&")
return data
def select_parse(request,ParseJson, ParseForm):
return

知识点回顾:

1.cbv

2.classmethod & classonlymethod

from django.utils.decorators import classonlymethod
class JinJa(object):
def __init__(self, name, age):
self.name = name
self.age = age @classmethod
def sleeping(cls):
print("sleeping") @classonlymethod
def shui(cls):
print("shui_jiao")
装饰器在类加载的时候执行。

3.getattr,hasattr,setattr

4.self定位

谁调用就是谁。

5.http请求协议

6.form enctype

7.JavaScriot object {name: "pizza"} =====>json转换

# 可以建立一个apps文件夹,将每个app放入其中
APPS_DIR= os.path.join(BASE_DIR, "apps")
sys.path.append(APPS_DIR)

2.view的请求流程

    1.通过as_view
def view(request, *args, **kwargs):
# 实例化一个对象,对象名称为self,self是cls的对象,谁调用cls
# cls就是谁(当前调用cls的是BookVIew)
# 所以,此时的self就是BookView的实例化对象
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.setup(request, *args, **kwargs)
返回函数 return self.dispatch(request, *args, **kwargs)
2.执行dispatch方法
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 此时的request对象指向原始的request对象
# 给self这个实例化对象赋值:原始的request(下面这行代码对request进行加工)
request = self.initialize_request(request, *args, **kwargs)
# 重新对request进行赋值
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
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
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

4.rest使用方式

1.from rest_framework.views import APIVIew
2.继承VPIView
class HomeView(APIVIew):
def get(self):
pass
3.url.py
from django.urls import path,include,re_path
urlpatterns = [
re_path('^course/$', views.CourseView.as_view()),
]
4.def post(self,request):
origin_data = request.data
......
return HttpResonse({})
源码剖析:request.data是从哪里来的?
1.dispatch方式中对request进行重新构造
request = self.initialize_request(request, *args, **kwargs) def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
)
# 1.1自己里面没有定义
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request
self.parsers = parsers or () # self.get_parsers()的结构
# 1.2还是在Requet里面找
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
# 1.3_load_data_and_files()
def _load_data_and_files(self):
if not _hasattr(self, '_data'):
self._data, self._files = self._parse() # 执行执行这个方法
if self._files:
self._full_data = self._data.copy()
self._full_data.update(self._files)
else:
if is_form_media_type(self.content_type):
self._request._post = self.POST
self._request._files = self.FILES
# 1.4 self._parse()
def _parse(self):
parser = self.negotiator.select_parser(self, self.parsers) # 解析器对象
parsed = parser.parse(stream, media_type, self.parser_context) # 解析之后的结果
return (parsed.data, parsed.files)
# 1.5 self.parsers # 获取解析器
def get_parsers(self):
return [parser() for parser in self.parser_classes]
# 1.6 self.parser_classes 一个属性
class APIView(View):
parser_classes = api_settings.DEFAULT_PARSER_CLASSES api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) # 因为找不到所以执行__getattr__方法
def __getattr__(self, attr):
try:
val = self.user_settings[attr] # 我们项目的settings文件中的默认参数
except KeyError:
# 没找到就去找rest的settings获取默认的参数
val = self.defaults[attr] # Coerce import strings into classes
if attr in self.import_strings:
val = perform_import(val, attr) # 这里的到的解析器类对象列表 # Cache the result
self._cached_attrs.add(attr)
setattr(self, attr, val)
return val # 这里返回的就是解析器列表
# 1.7 perform_import(val, "DEFAULT_PARSER_CLASSES")
# val是这个:
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
def perform_import(val, setting_name)
if val is None:
return None
elif isinstance(val, str):
return import_from_string(val, setting_name)
elif isinstance(val, (list, tuple)):
return [import_from_string(item, setting_name) for item in val]
return val
# 1.8
def import_from_string(dotted_path):
try:
module_path, class_name = dotted_path.rsplit('.', 1)
except ValueError as err:
raise ImportError("%s doesn't look like a module path" % dotted_path) from err module = import_module(module_path) # 动态导包进行包的获取 try:
return getattr(module, class_name)

super方法的解释
1.不使用super我们可以通过以下方式
class JinJa:
def __init__(self):
print("jinja is a parse")
class To:
def __init__(self):
To.__init__(self,)
2. 使用super方式
2.1 python2
class JinJa:
def __init__(self):
print("jinja is a parse")
class To:
def __init__(self):
super(TO,self).__init__(*args, **kwargs)# super(参数必须传递,self)有参数必须传递参数
2.2 python3
class JinJa:
def __init__(self):
print("jinja is a parse")
class To:
def __init__(self):
super().__init__(*args, **kwargs)# 有参数必须传递参数

*动态导包

import importlib
moudle = input("请输入要导入的模块:")
moudle = importlib.import_module(module)
# 通过字符串方式引入模块

知识点回顾:

1.三元运算:“alex” if a else "wusir"

2.列表推导式

3.getattr

4.djaong settiong文件查找顺序global_settings

5.动态import

6.Django原生的

5.序列化器

# django原生的serializer
from django.core.serializers import serialize
class CourseView(APIView):
# 这是局部的解析器,自定制的地方
parser_classes = [FormParser, JSONParser]
def get(self, request):
course_list = list()
cour = Course.objects.all()
for course in cour:
course_dict = {
"course_name": course.course_name,
"description": course.description,
}
course_list.append(course_dict)
ser_data = serialize("json", cour)
print(ser_data)
# ensure_ascii显示中文
return HttpResponse(json.dumps(course_list, ensure_ascii=False))
# 1.开始使用序列化类
- 导入模块
- 建立一个序列化类
- 获取queryset
- 开始序列化
- 获取序列化后的数据,返回给客户端
class BookSerializer(serializers.Serializer):
# nid = serializers.IntegerField()
title = serializers.CharField(max_length=32)
price = serializers.DecimalField(max_digits=10, decimal_places=2)
# 可以使用source字段覆盖当前的字段的显示,read_only只读字段
publish = serializers.CharField(max_length=32)
publish_name = serializers.CharField(read_only=True, max_length=32, source="publish.name")
city_name = serializers.CharField(read_only=True, max_length=32, source="publish.city")
# authors = serializers.CharField(max_length=32)
authors = serializers.SerializerMethodField() # instance是这次循环的书籍对象(额外字段都可以)
def get_authors(self, instance):
author_list = []
for author in instance.authors.all():
author_list.append(author.name)
return author_list # 如果用的是Serializer,这里需要你自己写create方法
def create(self, validated_data):
validated_data["publish_id"] = validated_data.pop('publish')
book_obj = Book.objects.create(**validated_data)
return book_obj class BookView(APIView):
def get(self, request):
# 获取queryset
origin_data = Book.objects.all()
# 将获取到的数据传入序列化类,数据多条是many=True
ser_data = BookSerializer(origin_data, many=True)
return Response(ser_data.data) def post(self, request):
client_data = request.data
ser_data = BookSerializer(data=client_data)
if ser_data.is_valid():
book = ser_data.save()
authors = Author.objects.filter(nid__in=request.data["authors"])
book.authors.add(*authors)
return Response(ser_data.data)
else:
return Response(ser_data.errors)
# 2.序列化器源码流程
- 1 每次传入的数据都是通过is_valid验证的
def is_valid(self, raise_exception=False):
# 其实就是判断数据有没有经过验证,但是第一次的数据,肯定没有验证
if not hasattr(self, '_validated_data'):
try:
# 所以执行run_validation, self.initial_data = data 传进来的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)
- 2 执行正真的验证数据的方法
def run_validation(self, data=empty):
# validate_empty_values是为了检验有一些值不需要传入的但是你却传入了,就是对于不需要进行验证值得一次过滤,比如read_only的字段就过滤掉了
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
value = self.to_internal_value(data)
# 这个是执行我们在serialzier类中定义的validate方法,你需要的逻辑可以在其中对于数据进行检验
value = self.validate(value)
self.run_validators(value)
return value
- 3 关键还是to_internal_value方法但是我读不进去了,
def to_internal_value(self, data):
ret = OrderedDict()
errors = OrderedDict()
# 拿到需要写入的字段,其中使用元类赋值的
fields = self._writable_fields for field in fields:
value = self.validate(value)
# 钩子函数方法,可以自定义对联合的字段进行验证,单字段检验,多字段需要使用validate方法
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
# 这里执行的每个字段自己的run_validation方法,其中还执行了自己的to_internal_value方法,我的意思是字段Field自己的而不是serialziers类自己的。
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
# 都没有问题的时候执行else
else:
set_value(ret, field.source_attrs, validated_value)
- run_validators这个方法其实就是我们自己写的验证器(用两种在序列化类执行的时候是Meta中的,而每个字段执行的时候是我们在每个字段中写的验证呢个列表)
def run_validators(self, value):
errors = []
for validator in self.validators:
if hasattr(validator, 'set_context'):
validator.set_context(self) try:
# 由于这里并没有接收参数,所以我们的序列化可以没有返回,只需要抛出错误即可;同时你可以在序列化类中使用slef给调用的实例对象,设置参数(如果你希望验证过后得到一个值的时候)。
validator(value)
except ValidationError as exc:
# If the validation error contains a mapping of fields to
# errors then simply raise it immediately rather than
# attempting to accumulate a list of errors.
if isinstance(exc.detail, dict):
raise
errors.extend(exc.detail)
except DjangoValidationError as exc:
errors.extend(get_error_detail(exc))
if errors:
raise ValidationError(errors)
- 4 获取字段
fields = self._writable_fields
@property
def _writable_fields(self):
for field in self.fields.values():
if not field.read_only:
yield field
- 5 关于slef.fields的来源这是非常关键的(找来找去找不到,在他继承的元类中找到了)
这里有一篇博客可以自己去看下,之后接着看源码https://www.cnblogs.com/machao/p/8708584.html
class SerializerMetaclass(type):
@classmethod
def _get_declared_fields(cls, bases, attrs):
# 然后我们发现我们serializer中定义的那些字段他全部是类属性,然后就可以同属性字典拿出来
fields = [(field_name, attrs.pop(field_name))
for field_name, obj in list(attrs.items())
if isinstance(obj, Field)]
# 就是根据创建的计数器大小排序
fields.sort(key=lambda x: x[1]._creation_counter)
# 然后还发现了一个好东西,reversed用来他继承的多个类反转一下,涉及到了类的多继承中mro
# 然后这里的作用就是将他继承的父类中的字段也加入到自己的fields字段中,其实就是serializer的嵌套时的字段处理过程,但是我写不出来啊,大佬还是大佬
for base in reversed(bases):
if hasattr(base, '_declared_fields'):
fields = [
(field_name, obj) for field_name, obj
in base._declared_fields.items()
if field_name not in attrs
] + fields return OrderedDict(fields) def __new__(cls, name, bases, attrs):
# 元类是在继承的类被创建的时候执行的它的__new__方法,可以看到里面执行了一个类方法
# 解释一下三个参数吧
# name就是自己类的名称,
# base就是除了继承的元类以外的其他继承类的一个元组
# attr是自己类的属性字典(是类的不是实例的)
attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
return super().__new__(cls, name, bases, attrs)
- 6 然后又执行了下面的代码
for field in fields: # 拿到每个字段,找到前面加validate的方法(自定义钩子函数对数据进行处理)
validate_method = getattr(self, 'validate_' + field.field_name, None) primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
else:
set_value(ret, field.source_attrs, validated_value)
- 7 field.get_value(data)注意这里开始执行的就是field的方法了不是self的,下面几个都是
# 是不是有点蒙,找不到了,然后突然发现CharField继承的是field,去它里面找,发现有
# 其实这个时候的field是什么有没有思考过,其实他就是CharField(max_length=32)
# 所以这里的这个get_valus是field中的,其实我第一遍找错了
def get_value(self, dictionary):
if html.is_html_input(dictionary):
return html.parse_html_dict(dictionary, prefix=self.field_name) or empty
# 拿出没有field_name对应的值返回
return dictionary.get(self.field_name, empty)
- 8 接下来执行了field.run_validation()方法
# CharField中有这个方法,但是它还是super了一下我们去看看
def run_validation(self, data=empty):
if data == '' or (self.trim_whitespace and str(data).strip() == ''):
if not self.allow_blank:
self.fail('blank')
return ''
return super().run_validation(data)
- 9 field中的run_validation
def run_validation(self, data=empty):
(is_empty_value, data) = self.validate_empty_values(data)
# 先去看第十步,如果is_empty_value为true就不检验
if is_empty_value:
return data
# 这里执行的每个字段中的to_internal_value方法
value = self.to_internal_value(data)
self.run_validators(value)
return value
# --------------CharField中的--------------------
def to_internal_value(self, data):
CharField中的除了(str, int, float,)其他都报错
if isinstance(data, bool) or not isinstance(data, (str, int, float,)):
self.fail('invalid')
value = str(data)
return value.strip() if self.trim_whitespace else value
# 记下来继续执行self.run_validators(value)方法,发现CharField中没有,可以自己定义,去field中找
def run_validators(self, value):
errors = []
# self.validator这个自己看在,field里面
for validator in self.validators:
# 说明validator中有一个属性叫做set_context
if hasattr(validator, 'set_context'):
validator.set_context(self)
try:
# 这里执行各自的验证逻辑
validator(value)
# 然后到这里基本就完了,还有一步,逻辑简单自己看吧
set_value(ret, field.source_attrs, validated_value)
# 所以字段都检验完了之后执行mate中的validtors方法,和字段中的类似,自己看一下 self.run_validators(value)
# 执行的是field中的run_validators,但是get_validators自己的serializer中有
def get_validators(self):
meta = getattr(self, 'Meta', None)
validators = getattr(meta, 'validators', None)
return list(validators) if validators else []
# 检验没出错就返回值
return(values)
- 10 执行field中的validate_empty_values
# 其中包括四种返回方式,
*引发“ValidationError”,表示数据无效。
*引发“SkipField”,表示该字段应该被忽略。
*返回(True, data),表示应该为空值返回,不应用任何进一步验证。
*返回(False, data),表示一个非空值,应该正常应用验证。
if self.read_only:
return (True, self.get_default())
if data is empty:
if getattr(self.root, 'partial', False):
raise SkipField()
if self.required:
self.fail('required')
return (True, self.get_default())
if data is None:
if not self.allow_null:
self.fail('null')
elif self.source == '*':
return (False, None)
return (True, None)
return (False, data)

注意:看序列化类的时候特别注意self,因为我看的有点模糊,第一次看的时候就没有分清。

其实到这里有没有人疑惑为什么,serializers可以点出来各种的XXField字段,看了半天没看出问什么?然后我就继续找,属性/方法,突然全局搜索了一下出来了,他直接全部给导入了,我还以为他继承了,但是一想继承也不可能啊。牛皮了

from rest_framework.fields import (  # NOQA # isort:skip
BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField,
DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField,
HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField,
ListField, ModelField, MultipleChoiceField, NullBooleanField, ReadOnlyField,
RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField,
)
from rest_framework.relations import ( # NOQA # isort:skip
HyperlinkedIdentityField, HyperlinkedRelatedField, ManyRelatedField,
PrimaryKeyRelatedField, RelatedField, SlugRelatedField, StringRelatedField,
)

知识点回顾:

1.解析器组件
- 解析器组件是用来解析用户请求的数据的(application/json), content-type
- 必须继承APIView
- request.data触发解析
2.序列化组件
2.1 Django自带的serializer
2.1.1 from django.serializer import serialize
2.1.2 Origin_data = Book.object.all()
2.1.3 serializer_data = serialzie("json", origin_data)
2.2 DRF的序列组件
- get 接口设计
2.2.1 from rest_framwork import serializers
2.2.2 创建一个序列化类
class BookSerialzier(serializer.Serializer):
publish_name = serializer(read_obly=True, source="publish.name")
authors_list = serialzier.SerializerMethodField() def get_authors_list(self, instance):
pass
2.2.3 开始序列化
origin_data = Book.objects.all()
ser_data = BookSerializer(data=origin_data, many=true)
return Response(ser_data.data)
- post接口设计
总结:
1.serializers.Serialzier无法插入数据,需要自己实现create
2.字段太多,不能自动序列化
- get 单条数据接口设计
1.定义url
2.获取数据对象
3.开始序列化:ser_data = BookSerializer(instance=book_obj)
4.返回数据: return Response(ser_data.data)
- delete
- put
1.定义url
2.获取数据对象
2.1 book_obj = Book.objects.get(pk=1)
3.开始序列化(验证数据,save(0))
3.1ser_data = BookSerializer(instance=book_obj, many=False)
4.返回数据: return Response(ser_data.data)
serializers.py
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
extra_kwargs = {
# "publish": {"write_only": True},
# "authors": {"write_only": True},
}
publish_name = serializers.CharField(read_only=True, max_length=32, source="publish.name")
city_name = serializers.CharField(read_only=True, max_length=32, source="publish.city")
# authors = serializers.SerializerMethodField() # def get_authors(self, instance):
# author_list = []
# for author in instance.authors.all():
# author_list.append(author.name)
# return author_list

6.今日内容:

今日内容:
1.接口设计
2.视图组件
- 试图组件是用来优化接口逻辑的
前提提要:
- 多继承
今日详细:
- 使用试图组件进行接口优化
- 使用试图组件mixin进行接口逻辑优化
from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin
from rest_framework.generics import GenericAPIView class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
注意:单条数据操作的url是这样的re_path('^book/(?P<pk>\d+)/$', views.BookFilterView.as_view()),
class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs) def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs) def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
- 使用试图组件的view进行接口逻辑优化
- 导入模块
from rest_framework import generic
- 写视图类
class BookView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer - 使用viewset优化接口逻辑
- 编写url
urlpatterns = [
re_path('^book/$', views.BookView.as_view(actions={
"get": "list",
"post": "create"
})),
re_path('^book/(?P<pk>\d+)/$', views.BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "destroy"
})),
]
- 导入模块
from rest_framework.viewset import ModelViewSet
- 设计视图类
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer

知识点回顾:

1.继续设计接口
1.1 post接口设计
- 如果使用serializer.Serialiezer会有如下问题:
1.需要手动插入数据(必须自定义create方法)
2.手动序列化需要的字段
- 为了解决上面的问题,我们建议使用serializer.ModelSerializer
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
extra_kwargs = {
# "publish": {"write_only": True},
# "authors": {"write_only": True},
}
publish_name = serializers.CharField(read_only=True, max_length=32, source="publish.name")
city_name = serializers.CharField(read_only=True, max_length=32, source="publish.city")
authors = serializers.SerializerMethodField() def get_authors(self, instance):
author_list = []
for author in instance.authors.all():
author_list.append(author.name)
return author_list
1.2 delete接口设计
class BookView(ApiView):
def delete(self, request, id):
obj = Book.objects.get(pk=id).delete()
reutrn Response()
1.3 put接口设计
class BooKFilterView(APIVIew):
def put(self,reqeust,id):
data = request.data
book_obj = Book.objects.get(pk=id) ser_data = BookSerializer(data=request.data, instance=book_obj,many=Flase) if ser_data.is_valid():
ser_data.save()
return Response(res_data.data)
else:
return Response(res_data.errors)
1.4 get获取单条
class BooKFilterView(APIVIew): def get(self,reqeust,id):
book_obj = Book.objects.get(pk=id)
ser_data = BookSerializer(instance=book_obj,many=Flase)
return Response(ser_data.data)
2.视图组件(mixin, genericview, viewset)
视图组件是用来优化接口逻辑的
2.1 使用mixin的使用
- 导入
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestoryModelMixin,RetireveModelMixin
from rest_framework.genericview import GenericAPIView
- 设计视图类
class BooKView(ListModelMixin, CreateModelMixin, GenericAPIView):
serializer_classes = BooKSerialzier
queryset = Book.objects.all() def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
2.2 mixin源码剖析

总结:

day:1
- 1.什么是编程
- 2.什么是rest
- 3.BS架构中,客户端通过url来访问客户端的资源(数据)
- 4.传统的url中设计里面包含动词(理论上来说,可以实现业务需求)
- 5.rest
url是唯一定位资源,http请求方式描述用户行为
GET:127.0.0.1:8001/books/ # 获取所有数据
GET:127.0.0.1:8001/books/id/ # 获取单挑数据
POST:127.0.0.1:8001/books/ # 增加数据
DELETE:127.0.0.1:8001/books/id/ # 删除数据
UPDATE:127.0.0.1:8001/books/id/ # 更改数据
返回规范:
GET:127.0.0.1:8001/books/ # 获取所有数据 返回[{}, ,]
GET:127.0.0.1:8001/books/id/ # 获取单挑数据 返回{}单条数据
POST:127.0.0.1:8001/books/ # 增加数据 返回{}添加成功
DELETE:127.0.0.1:8001/books/id/ # 删除数据 返回‘’返回空
put/UPDATE:127.0.0.1:8001/books/id/ # 更改数据 返回更新后的完整数据
错误处理
{"error":"error_message"}
- 6.CBV
- 定义view.py
from django.views import View
class BookView(View): def get(self. request):
pass def post(self, request):
pass
- 定义url.py
from django.urls import re_path urlpatterns = [
re_path("`book/$", views.BookVIew.as_view()),
] @classonlymethod
def as_view(cls, *arg, **kwargs):
def view(request):
self = cls(**args)
return self.dispath()
return view def dispatch(self,request):
if hasattr(self, self.method.lower(),):
handler = getattr(self, self.method.lower())
else:
raise
return handler(reqeust, *args, **kwargs)
- 7.django restframework
- 本质上是一个django app 用来帮助我们更快的开发出符合rest规范的web app
- pip install django
- pip install djangorestframework
- 定义views.py
from rest_framework.views import APIVIew
class ApiView(view);
@classonlymethod
def as_view(cls, request, *args, *8kwargs);
view = super(APIView, cls).as_view()
return view
def dispatch(self,request):
if hasattr(self, self.method.lower(),):
handler = getattr(self, self.method.lower())
else:
raise
return handler(reqeust, *args, **kwargs)
class BookView(APIView):
def get(self, reqeust):
pass
- 定义url.py
from django.urls import re_path url_parttrens = [
re_path("books/`$", BookView.as_view()),
]
- 8.drf解析器
- 定义views.py
from django.https import JsonResponse
from rest_framework.views import APIView
from rest_framework.reqeust import Request class Request(request): def __init__(self, parsers=get_parser()):pass def _parse(self):
parser = self.negotiator.select_parser(self, self.parsers)
parsed = parser.parse(stream, media_type, self.parser_context) return parsed.data, parsed
.files def _laod_data_and_file(self)
self.data, self.files = self._parse()
self._full_data = self.data @proparty
def data(self):
if not hasattr(self, "full_data"):
self._laod_data_and_files()
return self._full_data class APIVIew(View): parser_classes = apisettings.DEFAULT_PARSERS_CLASSES def get_parsers(self):
return [parser() for parsr in self.parser_classes] def initialize_request(self,request):
return Request(request,
parser = self.get_parsers()) def dispatch(self, request):
request = self.initialize_request(request, *args, **kwargs)
self.request = request
return response() class BookView(APIVIew):
def get(self. request):
pass def post(self, request):
request.data
return JsonResponse()
day2:
1.解析器组件
2.序列化组件
2.1 django原生的序列化
- 导入
from django.core serialziers import serialize
class BooVIew(APIVIew):
def get(self, request):
books = Book.object.all()
ser_data = serialzie("json", books)
return HttpResponse(ser_data)
2.2 drf序列化组件
- 导入
from rest_framework import serialzers
- 定义序列化类
class BooKSerializer(serializers.Serializer):
title = serializers.Charfield(max_length=32)
price = serializers.DecimalField()
publish = serialziers.CahrField(max_Lenght=32)
publish_name = serializers.CharField(max_lenght=32, source="publish.name", read_only=True)
authors_list = serializers.SerializerMethodField() def get_authors_lsit(self, instance):
authors = list()
for author in instance.authors():
authors.append(author.name)
return authors
def create(self, verified_data):
pass def updata(self, verified_data):
pass - 定义view.py
class BoosView(APIView):
def get(self, request):
books = Book.object.all()
ser_data = BooKserialzier(books, many=True)
reutnr Response(ser_data.data)
2.3 通过drf的序列化组件进行接口设计
2.4 通过drf的序列化组件进行POST接口设计
- 定义view。py
class BoosVIew(APIVIew);
def post(self, request):
data = request.data
ser_data = BooKSerialzier(data=data, many=False)
if ser_data.is_valid():
# BooKSerialzier没有实现写入操作即就是create方法
ser_data.save()
reutnr Response(ser_data.data)
else:
reutnr Response(ser_data.errors)
def put(self, request, id):
data = request.data
book_obj = Book.objects.get(pk=id)
ser_data = BooKSerialzier(instance=book_obj,data=data, many=False)
if ser_data.is_valid():
ser_data.save()
reutnr Response(ser_data.data)
else:
reutnr Response(ser_data.errors)
day3:
1.通过drf的序列化组件进行put接口设计
def put(self, request, id):
data = request.data
book_obj = Book.objects.get(pk=id)
ser_data = BooKSerialzier(instance=book_obj,data=data, many=False)
if ser_data.is_valid():
ser_data.save()
reutnr Response(ser_data.data)
else:
reutnr Response(ser_data.errors)
2.通过drf的序列化组件进行delete接口设计
3.通过drf的序列化组件进行get接口设计
4.试图组件
- 视图组件是用来优化接口逻辑的
4.1 mixins
- 导入
from rest_framework.mixins import (ListModelMixin,
CreateModelMixin,
UpdateModelMixin,
RetrieveModelMixin,
DestoryModelMixin)
from rest_framework.generics import GenericAPIView
- 定义序列化类
- urls.py
re_path('^book/$', views.BookView.as_view()),
re_path('^book/(?P<pk>\d+)/$', views.BookFilterView.as_view()),
- 定义view.py
class BookView(ListModelMixin, CreateModleMixin, GenericAPIVIiew):
queryset = Book.objects.all()
serialzier_class = BookSerializer def get(self, request):
pass
def psot(self, request):
pass class BookView(UpdateModelMixin,
RetrieveModelMixin,
DestoryModelMixin,
GenericAPiVIew):
queryset = Book.objects.all()
serialzier_class = BookSerializer def get(self, request, pk):
return self.retrieve(request)
def put(self, request, pk):
return self.update(request)
def delete(self, request, pk):
return self.destory(request)
4.2 genericview
- 导入
from rest_framework import generics
class BookView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serialzier_class = BookSerializer
class BookView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serialzier_class = BookSerializer
4.3 viewset
- 导入
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = Book.objects.all()
serialzier_class = BookSerializer
- url.py
urlpatterns = [
re_path('^book/$', views.BookView.as_view(actions={
"get": "list",
"post": "create"
})),
re_path('^book/(?P<pk>\d+)/$', views.BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "destroy"
})),
]

7.DRF之认证频率组件

7.1 认证类

1.认证类
1.1 使用方式
- 定义一个认证类
# 第一步:认证类
class UserAuth():
def authenticate_header(self, request):
pass # 认证逻辑
def authenticate(self, request):
user_token = request.query_params.get("token")
try:
token = UserToken.objects.filter(token=user_token).first()
return token.user.username, token.token
except Exception:
raise APIException("没有认证")
- 在需要认证的数据接口里面指定认证类
class BookView(ModelViewSet):
# 应用
authentication_classes = [UserAuth, ]
queryset = Book.objects.all()
serializer_class = BookSerializer
1.2 源码流程
1.初始化request
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request) return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
2. 通过requestt触发认证
self.perform_authentication(request)
def perform_authentication(self, request):
request.user
3. 执行user属性方法
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user # 赋值操作的时候执行
@user.setter
def user(self, value):
self._user = value
self._request.user = value
4. 执行 self._authenticate()
def _authenticate(self):
for authenticator in self.authenticators:
try:
# 这里调用自己写的认证类的authenticate方法进行认证
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
# 只要返回值不是None就可以通过认证
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
class Person():
@property
def name(self):
return self._name @name.setter
def name(self, value):
self._name = value

如何全局设置:

1.创建一个authencitation_classes.py文件
class UserAuth():
def authenticate_header(self, request):
pass # 认证逻辑
def authenticate(self, request):
user_token = request.query_params.get("token")
try:
token = UserToken.objects.filter(token=user_token).first()
# 这里因为有可能用到一下数据所以返回下面的数据,如果只是为类认证可以随意返回(不为None即可)
return token.user.username, token.token
except Exception:
raise APIException("没有认证") 2.在settings.py文件中全局引入
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'myapp.authencitation_classes.UserAuth',
],
}

注意事项:

假如有多个认证类(权限类)的话,我们只需要在最后一个认证类返回结果即可,因为在上面的第四步中,如果前面返回了正确的结果,他就不再循环验证后面的认证类。(其中认证类和权限类都有这个问题请注意)

4. 执行 self._authenticate()
def _authenticate(self):
for authenticator in self.authenticators:
try:
# 这里调用自己写的认证类的authenticate方法进行认证
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
# 只要返回值不是None就可以通过认证
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated() - 在需要认证的数据接口里面指定认证类
class BookView(ModelViewSet):
# 应用
authentication_classes = [UserAuth, UserAuth] # 多个认证类
queryset = Book.objects.all()
serializer_class = BookSerializer

7.2 权限类

1.权限类
1.1 使用方式
- 定义一个权限类
# 第一步:权限类
class UserPermission:
message = "你没有查看数据权限"
# 权限逻辑
def has_permission(self, request, view):
if request.user.user_type == 1:
return 1
return None - 在需要认证的数据接口里面指定认证类
class BookView(ModelViewSet):
# 应用
authentication_classes = [UserAuth, ]
queryset = Book.objects.all()
serializer_class = BookSerializer 1.2 源码流程
- 触发地点APIView的dispatch中
self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
self.check_permissions(request) # 权限检验
self.check_throttles(request)
- 权限检验函数
def check_permissions(self, request):
for permission in self.get_permissions():
# 这里可以看到permission就是我们写的权限类
# 下面触发了has_permission方法传入了request和view,只要返回的不为False就可以通过
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)

知识点回顾:

1.认证组件

	1.1 权限组件的使用
- 写一个认证类
class UserAuth():
def authenticate_header(self, request):
pass def authenticate(self, request):
# 通过
# 1.拿到用户传递的数据
# 2.拿到数据里面的token与用户传递的token进行比较
# 不通过
raise APIException
- 在试图类中指定认证类
class BookView(APIVIew):
authentication_classes = [UserAuth,]
- 可以指定多个认证类,需要注意的是,如果需要返回数据,请在最后一个认证类中返回
1.2 全局认证
- 在settiongs文件中指定
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'myapp.authencitation_classes.UserAuth',
],
}
2.权限组件
2.1 权限组件的使用
-定义个权限类
class UserPerm():
def has_permission(self,request, view):
if 有权限:
return True
else:
return False
- 在试图类中指定权限类
class BookView(APIVIew):
permission_classes = [UserPerm,]
- 可以指定多个权限类,需要注意的是,如果需要返回数据,请在最后一个权限类中返回
3.频率组件
3.1 频率组件的使用
-定义个频率类
class RateThrott():
def alow_reqeust(self,request, view):
if 没有超过频率:
return True
else:
return False
- 在试图类中指定频率类
class BookView(APIVIew):
permission_classes = [RateThrott,]
- 可以指定多个频率类,需要注意的是,如果需要返回数据,请在最后一个频率类中返回
3.2 使用DRF的简单频率空值来控制用户的访问频率
- 导入模块
from rest_framework.throttling import SimpleRateThrottle
- 定义并继承SimpleRateThrolle
class MYThrottle(SimpleRateThrottle):
# 指定访问频率
rate = "5/m"
# 通过什么方式区分用户
def get_cache_key(self, request, view):
return self.get_ident(request)
- 在试图类中指定频率类
class BookView(APIVIew):
permission_classes = [MYThrottle,]
- 可以指定多个频率类,需要注意的是,如果需要返回数据,请在最后一个频率类中返回
3.3 全局方式
- 导入模块
from rest_framework.throttling import SimpleRateThrottle
- 定义并继承SimpleRateThrolle
class MYThrottle(SimpleRateThrottle):
scope = "visit_rate"
def get_cache_key(self, request, view):
return self.get_ident(request)
- 在settiongs文件中指定
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [],
'DEFAULT_THROTTLE_RATES': {
'visit_rate': "5/m",
'anon': None,
},
}
- 源码例程
- 1.通过dispatch中的inintial方法中调用
self.check_throttles(request)
- 2.拿到频率器类之后访问其中的allow_request方法
def check_throttles(self, request):
throttle_durations = []
for throttle in self.get_throttles():
# 执行allow_request方法
if not throttle.allow_request(request, self):
throttle_durations.append(throttle.wait())
if throttle_durations:
durations = [
duration for duration in throttle_durations
if duration is not None
] duration = max(durations, default=None)
self.throttled(request, duration)
- 3.自己的类中没有allow_reqeust方法,去SimpleRateThrottle中找
def allow_request(self, request, view):
if self.rate is None:
return True # 获取一个唯一的key值,给没给用户进行标识
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
# 通过缓存拿取值
self.history = self.cache.get(self.key, [])
self.now = self.timer()
# 访问时间和现在时间减去间隔时间进行比较,如果小于呢个时间就弹出数据
# 可以理解为前一访问的时间+间隔时间<现在的时间(说明这是间隔时间已经够久了)
# 这时候说明这是时间是很久之前访问的,留在历史里面没用了,为了方便继续插入时间,弹出这个时间
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()
def throttle_success(self):
# 这里就是插入时间的地方,这代码写的很简洁(但是理解起来又点绕)
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
return True 而上面的self.num_requests哪里来的呢?在构造方法中可以看到,对self.rate进行了解析:
def __init__(self):
if not getattr(self, 'rate', None):
self.rate = self.get_rate()
self.num_requests, self.duration = self.parse_rate(self.rate)
# 如果没有发现rate值,就会去找scope,这个值是全局设置的时候使用的
def get_rate(self):
return self.THROTTLE_RATES[self.scope]
# 解析的结果是什么呢?其实就是将我们设置的rate进行分割
def parse_rate(self, rate):
if rate is None:
return (None, None)
num, period = rate.split('/')
num_requests = int(num)
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
return (num_requests, duration)
- 4. 在第二部中,发现如果结果返回为非真值
if not throttle.allow_request(request, self):
throttle_durations.append(throttle.wait())
def wait(self):
if self.history:
remaining_duration = self.duration - (self.now - self.history[-1])
else:
remaining_duration = self.duration
# 这里是对访问次数有进行了一次处理,如果访问次数大于设置的限制次数久之就返回None
# 其实进行测试之后发现,他是为了对如果我们设置的限制次数是负数的一种处理
available_requests = self.num_requests - len(self.history) + 1
if available_requests <= 0:
return None
return remaining_duration / float(available_requests)

关于自定义频率访问:

import math
import time from django.utils.translation import gettext_lazy as _ from rest_framework import exceptions
from rest_framework.throttling import SimpleRateThrottle from myapp.CustomException import MyThrottled # 自定义频率类
class VisitThrottle():
user_visit_information = dict()
visited_times = 1
period = 60
allow_times_per_minute = 5
first_time_visit = True def allow_request(self, request, view):
self.request_host = request_host = request.META.get("REMOTE_ADDR")
current_user_info = self.user_visit_information.get(request_host, None) if not self.__class__.first_time_visit:
self.user_visit_information[request_host][0] += 1
current_user_times = self.user_visit_information[request_host][0] # 如果访问次数,大于设置的次数就直接返回True
if current_user_times > self.allow_times_per_minute:
# 这就是第一次访问的时候的时间和当前访问的事件进行比较,如果在有效期间内
if self._current_time - current_user_info[1] <= self.period:
# 就更新或者设置已经过了多久的时间
if len(current_user_info) > 2:
current_user_info[2] = self._time_left
else:
current_user_info.append(self._time_left)
view.throttled = self.throttled
return None
else:
self.__class__.first_time_visit = True
# self.__class__是更新类变量而不是实例变量
if self.first_time_visit:
self.__class__.first_time_visit = False
self._initial_information() return True # 该函数返回一个响应值,用于给客户端展示,剩余多少秒可以尽心下次访问
def wait(self):
return self.period - self.user_visit_information[self.request_host][2] def throttled(self, request, wait):
raise MyThrottled(wait) @property
def _current_time(self):
return time.time() @property
def _time_left(self):
return math.floor(self._current_time - self.user_visit_information.get(self.request_host)[1]) def _initial_information(self):
self.user_visit_information[self.request_host] = [self.visited_times, self._current_time] # 使用rest_framework的频率类
class MYThrottle(SimpleRateThrottle):
rate = "5/m" def get_cache_key(self, request, view):
# 给请求的view挂在一个处理函数
view.throttled = self.throttled
return self.get_ident(request) def throttled(self, request, wait):
raise MyException(wait) # 这个是覆盖提示信息的类
class MyException(exceptions.Throttled):
default_detail = _("请求{wait}频率太快")
extra_detail_singular = extra_detail_plural = _('请{wait}秒之后访问.') def __init__(self, wait=None, detail=None, code=None):
# 走一下父类
super(MyException, self).__init__(wait, detail, code)

8.url注册其使用

- 导入模块
from rest_framework import routers
from django.urls import re_path, include
from myapp import views
- 生成一个注册器实例对象
router = routers.DefaultRouter()
- 将需要自动生成url的接口注册
router.register("books", views.BookView)
- 自动生成url
urlpatterns = [
re_path("^", include(router.urls))
]

9.响应器组件

- 导入模块
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
- 使用:
class BookView(ModelViewSet):
renderer_classes = [JSONRenderer]

10.分页器组件

1.分页器
1.1 简单使用
- 导入模块
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
- 获取取数据
books = Book.objects.all()
- 创建一个分页器对象
paginator = PageNumberPagination()
- 开始分页
paged_books = paginator.paginate_queyset(books, request)
- 开始序列化
ser_data = BookSerializer(books, many=True)
- 使用:
return Reponse(ser_data)
1.2 分页器组件局部使用
page_size = 2 # 每页显示多少条数据
page_query_param = "p" # 跳转到第几页(临时的通过url输入的)?p=3&size=3
page_size_query_param = "size" # 每页显示的数据条数(临时的通过url输入的)
max_page_size = 5 # 每页最多显示多少条数据
- 导入模块
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
- 定义一个分页器类继承PageNumberPagination
class MyPaginator(PageNumberPagination):
page_size = 2
page_query_param = "p"
page_size_query_param = "size"
max_page_size = 5
- 获取取数据
books = Book.objects.all()
- 实例化一个分页类对象
paginagor = MyPaginator()
- 开始分页
paged_books = paginator.paginate_queyset(books, request)
- 开始序列化
ser_data = BookSerializer(books, many=True)
1.3 全局使用
REST_FRAMEWORK = {
"PAGE_SIZE": 3,
'DEFAULT_PAGINATION_CLASS': "myapp.paginator_classes.MyPaginator",
}
1.4 关于分页器的源码解析
- 1.其中一个ListModelMixin中的分页器源码的流程
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# 这里触发分页
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
- 2.分页器真正的逻辑部分
def paginate_queryset(self, queryset):
if self.paginator is None:
return None
# 这里paginate_queryset才是我们自定义的分页器类的触发函数
return self.paginator.paginate_queryset(queryset, self.request, view=self)
@property
def paginator(self):
if not hasattr(self, '_paginator'):
if self.pagination_class is None:
self._paginator = None
else:
# 通过self.pagination_class()拿到我们在BookVIew中挂载的分页器类
self._paginator = self.pagination_class()
return self._paginator
- 3.返回的数据
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)

15.DRF学习以及相关源码阅读的更多相关文章

  1. 【 js 基础 】【 源码学习 】backbone 源码阅读(一)

    最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...

  2. 【 js 基础 】【 源码学习 】backbone 源码阅读(二)

    最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 ...

  3. 【 js 基础 】【 源码学习 】backbone 源码阅读(三)浅谈 REST 和 CRUD

    最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...

  4. 【 js 基础 】【 源码学习 】backbone 源码阅读(三)

    最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...

  5. 【第五篇】Volley代码修改之图片二级缓存以及相关源码阅读(重写ImageLoader.ImageCache)

    前面http://www.cnblogs.com/androidsuperman/p/8a157b18ede85caa61ca5bc04bba43d0.html 有讲到使用LRU来处理缓存的,但是只是 ...

  6. python3 源码阅读-虚拟机运行原理

    阅读源码版本python 3.8.3 参考书籍<<Python源码剖析>> 参考书籍<<Python学习手册 第4版>> 官网文档目录介绍 Doc目录主 ...

  7. Java源码阅读的真实体会(一种学习思路)

    Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...

  8. Java源码阅读的真实体会(一种学习思路)【转】

    Java源码阅读的真实体会(一种学习思路)   刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+ ...

  9. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

随机推荐

  1. Web Components的概念和用法

    参考链接:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components

  2. 4 基于优化的攻击——CW

    CW攻击原论文地址——https://arxiv.org/pdf/1608.04644.pdf 1.CW攻击的原理 CW攻击是一种基于优化的攻击,攻击的名称是两个作者的首字母.首先还是贴出攻击算法的公 ...

  3. mysql的授权命令

    #查看用户select user,host from mysql.user; (root,%),表示可以远程登录,并且是除服务器外的其他任何终端, 如CREATE USER 'azkaban'@'19 ...

  4. t-sql最短路径搜索

    SET STATISTICS IO ON; SET STATISTICS TIME ON; GO IF OBJECT_ID(N'dbo.t1') IS NOT NULL DROP TABLE dbo. ...

  5. Kick Start 2019 Round A Contention

    $\DeclareMathOperator*{\argmax}{arg\,max}$ 题目链接 题目大意 一排 $N$ 个座位,从左到右编号 $1$ 到 $N$ . 有 $Q$ 个预定座位的请求,第 ...

  6. 洛谷 P3370 【模板】字符串哈希 (set||map||哈希||字典树(mle)

    P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. #友情提醒:如果真的想好 ...

  7. 2019年8月22日 星期四(怎样成为PHP大牛)

    1.服务器方面,各种PHP部署方案烂熟,Lvs,keepalived,nginx,apache,docker,换句话说其战力值相当于一个高级运维,迅速定位并排除PHP运行中的各种问题. 2.数据库方面 ...

  8. [Nest] 02.nest之控制器

    控制器 Controller Nest 的核心概念 模块 Module 控制器 Controller 服务与依赖注入 Provider Dependency injection 控制器负责处理应用的特 ...

  9. sql--left join,right join, inner join

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...

  10. 客户端相关知识学习(一)之混合开发,为什么要在App中使用H5页面以及应用场景、注意事项

    混合开发 随着移动互联网的高速发展,常规的开发速度已经渐渐不能满足市场需求.原生H5混合开发应运而生,目前,市场上许多主流应用都有用到混合开发,例如支付宝.美团等.下面,结合我本人的开发经验,简单谈一 ...