1,
request.data
将传来的json数据解析成了字典的形式,我们可以使用request.data.get('')
来获取相应的值。我们知道原生django是不支持解析json
数据的,所以是DRF给解析了。为什么能解析json
类型呢?除了json
类型,别的类型还支持不支持?能不能自己限制只能解析json数据呢?这就需要继续研究了。从request入手。-
2,查看
APIView中的dispatch
发现,用initialize_request
方法进行变身,实例化了一个新的request对象并赋值给request- ①,这个方法前面一部分将request对象传进了
initialize_request
方法进行二次封装,形成了一个【新的request对象】
def dispatch(self, request, *args, **kwargs): request = self.initialize_request(request, *args, **kwargs) self.request = request
- ②,实例化了一个Request类的一个对象,返了回去【注意实例化过程中穿的参数:parsers(解析器的意思)】
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)
- ③,这个类在实例化的时候
class Request(object): def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None): self._request = request 【由此可见,新的request._request就是原来的request对象,但是我们一般不用,因为后续还做了处理】 self.parsers = parsers or () @property def query_params(self): return self._request.GET 【使用这个方法就可以得到源类的request对象的GET数据】
- ①,这个方法前面一部分将request对象传进了
-
3,在新的request类中找到了
request.data
这个方法,这才是真正解析的开始。-
①,Request类中的data方法,属性方法
@property def data(self): if not _hasattr(self, '_full_data'): self._load_data_and_files() return self._full_data
-
②,_load_data_and_files中,有一个
self._parse
方法def _load_data_and_files(self): if not _hasattr(self, '_data'): self._data, self._files = self._parse()
-
③,找到这个
_parse
方法def _parse(self): media_type = self.content_type 【拿到请求头中的数据类型】根据请求头中的数据类型,对应不同的解析器进行解析 parser = self.negotiator.select_parser(self, self.parsers)【self.parsers,选择解析器的步骤】 try: parsed = parser.parse(stream, media_type, self.parser_context)【解析的过程,不做仔细介绍】
-
④,选择解析器的过程中有一个
self.parsers
,这就回到了实例化的时候,返回查看Request类的init中:self.parsers = parsers or () 实例化request对象时:parsers=self.get_parsers()【此时的self是旧的,指的是自定义类的self某个对象】
-
⑤,自定义视图类的方法中,用了一个列表生成式,形成一个解析器对象的列表
def get_parsers(self): return [parser() for parser in self.parser_classes] 返回步骤③,查看select_parser,for循环解析器 def select_parser(self, request, parsers): for parser in parsers: if media_type_matches(parser.media_type, request.content_type): return parser
-
⑥,返回到了最初的自定义视图类的
perser_classes
中如果自己设置了就用自己的,自己没设置就用父类的。 1,自己设置的情况可以理解。 2,自己没设置,用父类的情况(APIView): parser_classes = api_settings.DEFAULT_PARSER_CLASSES 【api_settings】点了一下属性,但是没有此属性 api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) 【APISettings实例化的对象】 【DEFAULTS是配置文件里面的一个个键值对】 所以走了__getattr__方法 def __getattr__(self, attr): try: val = self.user_settings[attr] 【执行了此函数,得出的应该是一个字典,且拿到了执行后的attr的对应值】 except KeyError: val = self.defaults[attr] 【全局找不到,就走默认】 @property def user_settings(self): if not hasattr(self, '_user_settings'): self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})【此setting是原生django的】 return self._user_settings settings = LazySettings()【一个LazySettings对象】 from django.conf import settings 这个是django的全局配置
-
-
4,步骤⑥的具体解析:
1,parser_classes = api_settings.DEFAULT_PARSER_CLASSES 2,api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) 3,class APISettings(object): def __init__(self, user_settings=None, defaults=None, import_strings=None): if user_settings: self._user_settings = self.__check_user_settings(user_settings) self.defaults = defaults or DEFAULTS self.import_strings = import_strings or IMPORT_STRINGS self._cached_attrs = set() 4,api_settings.DEFAULT_PARSER_CLASSES 点不到,就会找__getattr__方法 5,def __getattr__(self, attr):【attr就是找不到的这个DEFAULT_PARSER_CLASSES】 try: 【如果报错,就走下面】 val = self.user_settings[attr] 【⑥⑦⑧解析】 except KeyError: val = self.defaults[attr] --》【默认配置】 return val 6,@property def user_settings(self): if not hasattr(self, '_user_settings'): 【没有这个属性,走下面↓】 self._user_settings = getattr(settings, 'REST_FRAMEWORK', {}) return self._user_settings 7,self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})【settings是两个settings加起来一起】 全局的源码级别的改不了,所以只能从自己的项目里的settings中改。 如果自己配置了,就返回自己配置的那个,没配置就返回空字典。 8,配置了REST_FRAMEWORK,但是取不到值就报错。 空字典[attr]也报错,只要报错就走下面。 也就是说想要走这个,必须配置REST_FRAMEWORK并且里面有对应的键。
最后得到查找顺序:
1,先找自己视图类里面的。
2,找不到自己的找全局(django的本项目中的setting)。
3,再找就是默认(rest_framework这个包中的setting)。