Я вижу здесь 2 проблемы:
- Неправильные представления о
class-based views
в django
- Неправильные представления о
object-
и class-
методах в python
Давайте посмотрим более подробно.
1.Представления на основе классов Django
Это должно звучать странно (особенно для новичков), но class-based view
в django не означает, что вы привязываете методы objects
/ classes
к url
-байтам.
Более того:
django.urls.path
могут использовать только функции fn(request, *args, **kwargs)
Pythonic it's better explicite
для self
-парам делает object-methods
непригодным для views
(по крайней мере, без "особой магии").
Так в чем смысл class-based views
?
https://github.com/django/django/blob/2bc014750adb093131f77e4c20bc17ba64b75cac/django/views/generic/base.py#L48
На самом деле все очень просто:
class-based view
метод выставления класса as_view
as_view
являетсяфункция высокого порядка и не используется непосредственно в path
/ url
вызовах. as_view
создает фактическую функцию представления во время выполнения - сгенерированная функция также не очень сложна.Грубо говоря, он ищет существование определенных
get
/ post
/ put
/ head
-методов, вызывает их, когда они существуют, и вызывает исключения, когда их не существует.
Итак, вы можете видеть, что «человек не просто привязывает методы представления классов к URL-маршрутам в django».
Это инструмент, который вряд ли можно рекомендовать для общего пользования.в случаях, когда это негибкость желательна.
2.object-
, class-
, static-
методы
ОК.Теперь вторая проблема.
Можем ли мы вызывать из class-based view
методы других методов?
Да, мы можем, но с некоторыми ограничениями.
Давайте рассмотрим демо one-file
в django 2.0.(Для 1.11 - %s/path/url/g
)
from django.urls import path
from django.http import HttpResponse
from django.utils.decorators import classonlymethod
# CASE 1: normal function - OK
def just_a_fun(request, **kwargs):
context = kwargs if kwargs else {"method": "just a function"}
return HttpResponse('method = %(method)s' % context)
class ViewClass(object):
def get(self, request, **kwargs):
return just_a_fun(request, **kwargs)
# CASE 2: Object method - FAIL, not possible to use in `django.url.path`-calls
def om_view(self, request):
return self.get(request, **{"method": "object method"})
# CASE 3: class method - OK
@classmethod
def cm_view(cls, request):
return cls.get(cls, request, **{"method": "class method"})
# CASE 4: static method - FAIL, not possible to call `cls.get` or `self.get`
@staticmethod
def sm_view(request):
self = None # This is a problem with static methods
return self.get(self, request, **{"method": "static method"})
# CASE 5: HOF-view, similar to django.views.generic.View.as_view - OK
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, **kwargs):
self = cls(**initkwargs) # Object construction
self.request = request
self.kwargs = kwargs
return self.get(request, **{"method": "HOF as_view"})
return view
urlpatterns = [
path("just-a-fun", just_a_fun), # OK
path("object-method",
ViewClass.om_view), # Problem: redundant `self` for `path`
path("class-method", ViewClass.cm_view), # OK
path('static-method',
ViewClass.sm_view), # Problem: not possible to call `get`
path('hof-view', ViewClass.as_view()), # OK.
]
Резюме:
- Обычные функции лучше всего подходят
- Объектные методы не могут использоваться (по крайней мере, без некоторых"особая магия")
- Методы класса: без проблем.Но имейте в виду, что методы класса могут использовать только другие методы класса
- Статические методы: хорошо для использования в вызовах
path
/ url
, но они не могут использовать другие методы классов - Если вы действительно хотите использовать ООП: вы можете сделать это «способом django» - создайте HOF, которые будут генерировать реальные функции представлений во время выполнения.Посмотрите на
django.views.generic
исходный код для вдохновения
...
Я надеюсь, что все должно проясниться, но вопросы, критика, исправления - милости просим!