面向对象和反射的一些补充说明
class Animal:
def __init__(self, name, age, func_str):
self.name = name
self.age = age
# self 指的是类实例对象,此处指的是 Dog 的实例对象
# 所以如果 Dog 中重写了 sleep 方法,那么 self.sleep() 调用的就是 Dog 中的 sleep 方法
# 如果 Dog 中没有重写, self.sleep() 调用的才是 Animal 中的 sleep 方法
self.sleep()
# 反射
# func 为 func_str 对应的方法
# 如 func_str = "sleep", 那么 getattr 返回的就是 sleep 方法
# 即 func = sleep
func = getattr(self, func_str) # => self.func_str
func() # 调用方法
def sleep(self):
print("sleep....")
def eat(self):
print("eat...")
class Dog(Animal):
def sleep(self):
print(f"{self.name} sleep....")
dog = Dog("旺财", 2, "sleep")
CBV 的简单使用
views.py 文件代码
# views.py 文件
from django.views import View
# CBV: 基于类的视图
class BookView(View):
# 当前段发送 GET 请求时,会执行 get 方法,方法名为对应的请求类型,不能随便修改
def get(self, request):
return HttpResponse("GET 请求....")
# 当前段发送 POST 请求时,会执行 post 方法
def post(self, request):
return HttpResponse("POST 请求...")
# 当前段发送 DELETE 请求时,会执行 delete 方法
def delete(self, request):
return HttpResponse("DELETE 请求....")
urls.py 文件代码
# urls.py 文件
from .views import BookView
urlpatterns = [
path('book/', BookView.as_view()),
}
对 urls.py 文件中的 BookView.as_view() 进行分析
BookView.as_view() 最终指的是 django.views.View 中的 as_view()。
as_view() 源码如下,也就是说调用 as_view() 方法,最终会返回一个 view 方法,所以 django 启动时, 执行语句 BookView.as_view() 得到一个方法 view , 即 path('book/', BookView.as_view()) => path('book/', view) 。由此可以看出 CBV 的本质还是 FBV (基于函数的视图)。
# as_view() 源码解读
as_view() 方法是在 django.views.View 中
as_view() 源码的关键部分如下:@classonlymethod
def as_view(cls, **initkwargs):
# do something....def view(request, *args, **kwargs):
# do something....# do something....
return view
当用户以 get 请求(或者其他请求)访问 “/book/” 时,就会执行 view() 方法,即 get 请求访问 /book/ => view() => dispatch()
对 as_view() 方法中的 view() 方法进行分析
@classonlymethod def as_view(cls, **initkwargs): # do something... def view(request, *args, **kwargs): # cls 指向 BookView 类,因为是 BookView 调用的 as_view() # 创建一个 BookView 类实例对象,此处等价于 self = Bookview(**initkwargs) self = cls(**initkwargs) self.setup(request, *args, **kwargs) # do something... # self.dispatch() 先去 BookView 类中查找 dispatch 方法 # 如果找不到,再找 BookView 父类,即 View # 所以 self.dispatch() 访问的是 View 中的 dispatch 方法 return self.dispatch(request, *args, **kwargs) # do something... return view
对 django.views.View 类中的 dispatch() 方法进行分析
所以当用户以 get 请求(或者其他请求)访问 “/book/” 时,就会执行 view() 方法,即 get 请求访问 /book/ => view() => dispatch() => handler() => get(),即 BookView 中的 get() => get() 方法中 return HttpResponse("GET 请求....")
而如果用户以 post 请求(或者其他请求)访问 “/book/” 时,也会执行 view() 方法,即 post 请求访问 /book/ => view() => dispatch() => handler() => post(),即 BookView 中的 post() => post() 方法中 return HttpResponse("POST 请求....")
所以 dispatch 称为分发,因为不管前端发送什么请求,最后都会通过 dispatch 分发到对应的视图函数中,执行相应的逻辑。
def dispatch(self, request, *args, **kwargs): """ 下面的 if-else 的核心就是: handler = getattr(self, request.method.lower()) 即文章开头提到的反射:handler = self.request.method.lower() 现假设以 get 请求访问 /book/, 则代码变为 handler = self.get 此处的 self 是 BookView 类的实例对象 所以 handler 为 BookView 类中的 get 方法 对应上了 BookView 类中定义的 get """ # http_method_names = ["get","post","put","patch", # "delete","head","options","trace",] """ 如果请求方法不在允许的列表里,或者 self 实例对象中没有改请求方法 则 handler = self.http_method_not_allowed 即执行不允许的请求方法 """ 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 # 调用 handler(),并将其方法调用后的结果返回 return handler(request, *args, **kwar