restframework安装
1.下载pip install djangorestframework
2.使用时:在INSTALLED_APPS加入"rest_framework"
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', "rest_framework" ]
restful协议
url
一切皆资源
book / add
books
book / 1 / change
book / 1 / delete
在restful中:
books - ------get :查询所有书籍 - ------- 返回的查询的所有书籍
books - ------post :添加一本书籍 - ------- 返回的添加书籍
books / 1 - ------get :查看某本书籍 - ------- 返回的这本书籍
books / 1 - ------put / patch :编辑某本书籍 - ---返回的编辑后的书籍
books / 1 - ------delete :删除某本书籍 - ---返回空
CBV流程解析
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^book/', views.BookView.as_view()), url(r'^book/(\d+)', views.BookDetailView.as_view()), ]
请求走到url中,怎么执行的?
1.执行View中的as_view,返回结果view
2.执行View中的view,返回结果self.dispatch,self为自定义的类的对象,自定义类中无dispatch方法
就执行View中的dispatch
3.执行View中的dispatch,利用反射执行对应的请求函数
class BookView(View): def get(self,request): return HttpResponse("get.........") def post(self,request): return HttpResponse("post........")
1.请求找到 url(r'^book/', views.BookView.as_view())这条路由,执行views.BookView.as_view()
views.BookView是我们在views中自定义的类,在这里调用了as_view,那么as_view应该是类中的属性或方法,
而自定义的类中没有as_view,应该去其父类中查找
去View中查找as_view,查看源码及进行分析
class View(object): @classonlymethod def as_view(cls, **initkwargs): """ Main entry point for a request-response process. """ for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view
as_view是类方法,views.BookView.as_view()的结果是view
url(r'^book/', views.BookView.as_view()),相当于 url(r'^book/', view) 根据函数式路由猜测views应返回一个函数名
url(r'^book/', view) 一旦用户访问book 执行的是view(request),view返回了什么,在页面上就应该显示什么
2.执行View中的view:
view的源码
def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs)
view的执行结果是return self.dispatch(request),self是BookView的对象,去找dispatch方法,如果未定义,就去找父类View中的dispatch
3.View中的dispatch
def dispatch(self, 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 return handler(request, *args, **kwargs)
所有的请求方式:http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
当前请求在请求方式中的话,就利用反射调用请求方法
url(r'^books/', view), # 一旦用户访问books 执行的是view(request)======self.dispatch(request)========self.get(request)
1.BookView中无dispatch,执行View中的dispatch
如果是get/post请求,就执行BookView中的get/post
class BookView(View): def get(self,request): return HttpResponse("get.........") def post(self,request): return HttpResponse("post........")
2.BookView中有dispatch,则不再执行View中的dispatch
class BookView(View): def dispatch(self, request, *args, **kwargs): print("dispatch......") def get(self,request): return HttpResponse("get.........") def post(self,request): return HttpResponse("post........")
无论是post还是get请求,均不会执行BookView中的get/post方法。因为BookView中有dispatch则不会执行
View中的dispatch。在BookView中dispatch没设置返回值,页面会报错,在服务器后端显示dispatch.......
3.即执行BookView中的dispatch又执行Views中的dispatch
class BookView(View): def dispatch(self, request, *args, **kwargs): print("dispatch.......") ret=super().dispatch(request, *args, **kwargs) return ret def get(self,request): return HttpResponse("get.........") def post(self,request): return HttpResponse("post........")
好处:可以添加额外的功能
APIview流程
1.执行APIView中的as_view,返回的结果super(APIView, cls).as_view(**initkwargs)
2.执行View中的as_view,返回结果view
3.执行View中的view,返回结果self.dispatch,self为自定义的类的对象,自定义类中无dispatch方法
就执行APIview中的dispatch
4.执行APIview中的dispatch,利用反射执行对应得请求函数,同时将原生得request进行封装
1.在url中设计两条路由:
url(r'^book/', views.BookView.as_view()), url(r'^book/(\d+)', views.BookDetailView.as_view()), url(r'^book/', views.BookView.as_view())完成查询所有书籍和添加书籍的操作 url(r'^book/(\d+)', views.BookDetailView.as_view())完成查看某本书籍,编辑某本书籍和删除某本书籍的操作
2.使用APIView
from rest_framework.views import APIView class BookView(APIView): def get(self,request): book_obj=models.Book.objects.all() #将每个对象都取出来,放到列表中,序列化后返回 temp=[] for obj in book_obj: temp.append({ "pk":obj.pk, "title":obj.title }) return HttpResponse(json.dumps(temp)) def post(self,request): return HttpResponse("post........")
1.在执行url时,执行views.BookView.as_view(), BookView中无as_view
去父类APIView中查找
class APIView(View): @classmethod def as_view(cls, **initkwargs): if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( 'Do not evaluate the `.queryset` attribute directly, ' 'as the result will be cached and reused between requests. ' 'Use `.all()` or call `.get_queryset()` instead.' ) cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs return csrf_exempt(view)
views.BookView.as_view()的结果是view,查看view
2. view的值是View中as_view的返回值
view = super(APIView, cls).as_view(**initkwargs)
执行APIView父类View中as_view方法:
class View(object): @classmethod def as_view(cls, **initkwargs): def as_view(cls, **initkwargs): pass def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs return view
3.执行View中的view方法,结果执行self.dispatch(request, *args, **kwargs),
BookView无dispatch方法,执行APIView中的dispatch方法
4. 执行APIView中的dispatch方法
class APIView(View): def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) # Get the appropriate handler method 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 try中的代码和View中dispatch的代码相同,均是利用反射执行对应的请求函数 class View(object): def dispatch(self, 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 return handler(request, *args, **kwargs)
5.封装APIView中dispatch方法中的request
但两者的request是不同的,View中dispatch的request是原生的request
而APIView中的dispatch方法中后续使用的request是封装过的request
def dispatch(self, request, *args, **kwargs): request = self.initialize_request(request, *args, **kwargs) self.request = request
在dispatch中,将原生的request作为initialize_request方法中的参数,执行后返回一个Request对象,将封装后的这个对象赋给request
之后使用的request都是封装后的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 )
查看Request这个类:
class Request(object): self._request = request self.parsers = parsers or () self.authenticators = authenticators or () self.negotiator = negotiator or self._default_negotiator() self.parser_context = parser_context self._data = Empty @property def query_params(self): return self._request.GET 其中的_request属性的值就是原生的类,可通过调用这个属性来查看原生类的值
1.在发送get时,打印接收值
from rest_framework.views import APIView class BookView(APIView): def get(self,request): print(request.GET) print(request._request.GET) print(request.query_params) return HttpResponse("ok") <QueryDict: {'title': ['go']}> <QueryDict: {'title': ['go']}> <QueryDict: {'title': ['go']}> query_params和_request.GET是一样的
2.使用post请求
使用post请求时,原生的request只能解析urlencode数据使用封装后的request.data有着多种解析器
使用urlencoded解析:
def post(self,request): print("request.Post:",request.POST) print("request.data:", request.data) #获取值: print("request.data:", request.data["title"]) return HttpResponse("post........") request.Post: <QueryDict: {'title': ['c++']}> request.data: <QueryDict: {'title': ['c++']}>
其它解析:
request.Post: <QueryDict: {}> request.data: {'title': 'c++'} request.data: c++