Классовые представления в Джанго
Django view указывает на функцию, которая может быть проблемой, если вы хотите изменить только немного функциональности. Да, я мог бы иметь миллион ключевых аргументов и даже больше, если бы операторы в функции, но я больше думал об объектно-ориентированном подходе.
Например, у меня есть страница, которая отображает пользователя. Эта страница очень похожа на страницу, которая отображает группу, но она все еще не так похожа, просто используйте другую модель данных. Группа также имеет членов и т.д...
Один из способов - указать методы на методы класса, а затем расширить этот класс. Кто-нибудь пробовал этот подход или есть другая идея?
9 ответов
Я создал и использовал свои собственные классы общего вида, определяя __call__
поэтому экземпляр класса может быть вызван. Мне это и вправду нравится; в то время как общие представления Django допускают некоторую настройку с помощью аргументов ключевых слов, общие представления OO (если их поведение разбито на несколько отдельных методов) могут иметь гораздо более детальную настройку с помощью подклассов, что позволяет мне повторяться намного меньше. (Я устаю переписывать одну и ту же логику создания / обновления представления в любое время, когда мне нужно настроить что-то общее, чего не позволяют обычные представления Django).
Я разместил некоторый код на djangosnippets.org.
Единственный реальный недостаток, который я вижу, - это распространение внутренних вызовов методов, что может несколько повлиять на производительность. Я не думаю, что это сильно беспокоит; редко, когда выполнение кода на Python становится вашим узким местом в веб-приложении.
ОБНОВЛЕНИЕ: собственные общие представления Django теперь основаны на классах.
ОБНОВЛЕНИЕ: FWIW, я изменил свое мнение о взглядах на основе классов, так как этот ответ был написан. После интенсивного их использования в нескольких проектах, я чувствую, что они имеют тенденцию приводить к коду, который достаточно СУХОЙ для написания, но очень трудным для чтения и сопровождения в дальнейшем, потому что функциональность разбросана по стольким разным местам, а подклассы так зависимы на каждой детали реализации суперклассов и миксинов. Теперь я чувствую, что TemplateResponse и декораторы представлений - лучший ответ для декомпозиции кода представления.
Мне нужно было использовать представления, основанные на классах, но я хотел иметь возможность использовать полное имя класса в моем URLconf, не всегда создавая экземпляр класса представления перед его использованием. Мне помог удивительно простой метакласс:
class CallableViewClass(type):
def __call__(cls, *args, **kwargs):
if args and isinstance(args[0], HttpRequest):
instance = super(CallableViewClass, cls).__call__()
return instance.__call__(*args, **kwargs)
else:
instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
return instance
class View(object):
__metaclass__ = CallableViewClass
def __call__(self, request, *args, **kwargs):
if hasattr(self, request.method):
handler = getattr(self, request.method)
if hasattr(handler, '__call__'):
return handler(request, *args, **kwargs)
return HttpResponseBadRequest('Method Not Allowed', status=405)
Теперь я могу как создавать экземпляры классов представления, так и использовать экземпляры в качестве функций представления, ИЛИ я могу просто указать свой URLconf на мой класс и получить метакласс для создания (и вызова) класса представления для меня. Это работает, проверяя первый аргумент __call__
- если это HttpRequest
, это должен быть фактический HTTP-запрос, потому что было бы бессмысленно следить за тем, чтобы создать экземпляр класса представления с HttpRequest
пример.
class MyView(View):
def __init__(self, arg=None):
self.arg = arg
def GET(request):
return HttpResponse(self.arg or 'no args provided')
@login_required
class MyOtherView(View):
def POST(request):
pass
# And all the following work as expected.
urlpatterns = patterns(''
url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
url(r'^myview2$', myapp.views.MyView, name='myview2'),
url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)
(Я разместил фрагмент для этого на http://djangosnippets.org/snippets/2041/)
Если вы просто отображаете данные моделей, почему бы не использовать общие представления Django? Они предназначены для того, чтобы вы могли легко отображать данные из модели без необходимости писать собственный вид и рассказывать о сопоставлении параметров URL с представлениями, выборке данных, обработке краевых случаев, выводе рендеринга и т. Д.
Вы всегда можете создать класс, переопределить __call__
функции, а затем укажите URL-файл на экземпляр класса. Вы можете взглянуть на класс FormWizard, чтобы увидеть, как это делается.
Похоже, вы пытаетесь объединить вещи, которые не должны быть объединены. Если вам необходимо выполнить различную обработку в вашем представлении, в зависимости от того, на какой объект вы пытаетесь взглянуть: пользователь или группа, вам следует использовать две разные функции представления.
С другой стороны, могут быть общие идиомы, которые вы хотели бы извлечь из представлений типа object_detail... возможно, вы могли бы использовать декоратор или просто вспомогательные функции?
Дан
Если вы не хотите делать что-то немного сложное, использование универсальных представлений - путь. Они гораздо более мощные, чем предполагает их название, и если вы просто отображаете данные модели, общие представления сделают свою работу.
Обычные представления обычно подходят, но в конечном итоге вы можете обрабатывать URL-адреса по своему усмотрению. FormWizard работает на основе классов, как и некоторые приложения для API RESTful.
В основном, с помощью URL вы получаете кучу переменных и место для обеспечения возможности вызова. То, что вы вызываете, полностью зависит от вас - стандартный способ - предоставить функцию - но в конечном итоге Django не накладывает никаких ограничений на то, что вы делаете.
Я согласен, что еще несколько примеров того, как это сделать, было бы неплохо, хотя FormWizard - это то, с чего стоит начать.
Вы можете использовать общие виды Django. Вы можете легко достичь желаемой функциональности с помощью общих видов Django.
Если вы хотите поделиться общими функциями между страницами, я предлагаю вам взглянуть на пользовательские теги. Их довольно легко создать, и они очень мощные.
Также шаблоны могут расширяться от других шаблонов. Это позволяет вам иметь базовый шаблон для настройки макета страницы и делиться этим между другими шаблонами, которые заполняют пробелы. Вы можете вкладывать шаблоны на любую глубину; позволяя указать макет на отдельных группах связанных страниц в одном месте.