Django View Types

Django View Types

Basic information

  • Django version: 2.1

Introduction

當一個 HTTP request被WSGI server接收時,在WSGIHandler中會根據url.py配置,找到對應的view function
相應代碼在WSGIHandler父類BaseHandler @django/core/handlers/base.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BaseHandler:
def _get_response(self, request):
# ...
resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match
request.resolver_match = resolver_match
# ...
if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
response = self.process_exception_by_middleware(e, request)

wrapped_callback就是View function,上述可知,View function是一個接收三個參數的function

Django View Types

Django常用的view可以分為以下兩類

  • FBV(Function Based View)

    • 優點
      • 寫法容易,容易理解
      • 可以直接使用Decorator
    • 缺點
      • 不便於繼承與重用
      • 處理HTTP methods時,需要在內部使用條件判斷處理
    • 示例

      1
      2
      3
      4
      path("", index)
      def index(request):
      return HttpResponse("It is the index page")
  • CBV(Class Based View)

    • Django提供許多Built-in class-based views,分成以下兩類
      • Base views
        • 提供最基本的常用功能,可以直接使用或者繼承後使用
        • Generic views的父類
      • Generic views
        • 提供常用的功能,例如數據展現或修改頁面
        • 常用功能與對應Generic views如下:
          • Display views
            • ListView: 展現數據列表
            • DetailView: 展現特定數據的詳細資料
          • Edit views
            • FormView: 用戶填寫Form後轉跳到對應頁面
            • CreateView: 透過Form創建某項數據
            • UpdateView: 更改數據資料
            • DeleteView: 刪除數據
          • Generic date views
            • ArchiveIndexView: 從最近日期開始顯示數據列表
            • YearArchiveView: 根據年過濾顯示數據列表
            • MonthArchiveView: 根據年/月過濾顯示數據列表
            • WeekArchiveView: 根據年/週過濾顯示數據列表
            • DayArchiveView: 根據年/月/日過濾顯示數據列表
            • TodayArchiveView: 根據今日過濾顯示數據列表
            • DateDetailView: 顯示特定日期數據的詳細資料
    • 可以搭配Class-based views mixins使用
    • 上述提到View function只能是一個接收三個參數的function,Django在所有View的父類View @django/views/generic/base.py 提供一個as_view方法,可將CBV轉換成View function
    • 當WSGIHandler的調用View function時,as_view內部會呼叫自身的dispatch,dispatch會根據http method調用View所實作對應名稱的function

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      class View:
      @classonlymethod
      def as_view(cls, **initkwargs):
      # ...
      def view(request, *args, **kwargs):
      print("[View] cls to init object")
      self = cls(**initkwargs)
      if hasattr(self, 'get') and not hasattr(self, 'head'):
      self.head = self.get
      self.setup(request, *args, **kwargs)
      if not hasattr(self, 'request'):
      raise AttributeError(
      "%s instance has no 'request' attribute. Did you override "
      "setup() and forget to call super()?" % cls.__name__
      )
      return self.dispatch(request, *args, **kwargs)
      # ...
      return view
      def dispatch(self, request, *args, **kwargs):
      # Try to dispatch to the right method; if a method doesn't exist,
      # defer to the error handler. Also defer to the error handler if the
      # request method isn't on the approved list.
      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)
    • 示例

      1
      2
      3
      4
      5
      path("", IndexView.as_view())
      class IndexView(View):
      def get(self, request, *args, **kwarg):
      return HttpResponese("It is the index page")