Классовые представления в Джанго - PullRequest
51 голосов
/ 03 августа 2008

Django просмотр указывает на функцию, которая может быть проблемой, если вы хотите изменить только немного функциональности. Да, я мог бы иметь миллион ключевых аргументов и даже больше, если бы операторы в функции, но я больше думал об объектно-ориентированном подходе.

Например, у меня есть страница, которая отображает пользователя. Эта страница очень похожа на страницу, которая отображает группу, но она все еще не так похожа, просто используйте другую модель данных. Группа также имеет членов и т.д ...

Одним из способов было бы указать представления на методы класса, а затем расширить этот класс. Кто-нибудь пробовал этот подход или есть другая идея?

Ответы [ 9 ]

42 голосов
/ 29 августа 2008

Я создал и использовал свои собственные классы общего вида, определяя __call__, поэтому экземпляр класса может быть вызван. Мне это и вправду нравится; в то время как общие представления Django допускают некоторую настройку с помощью аргументов ключевых слов, общие представления ОО (если их поведение разбито на несколько отдельных методов) могут иметь гораздо более детальную настройку с помощью подклассов, что позволяет мне повторяться намного меньше. (Я устаю переписывать одну и ту же логику создания / обновления представления в любое время, когда мне нужно настроить что-то общее, чего не позволяют Джанго общие представления).

Я разместил код на djangosnippets.org .

Единственный реальный недостаток, который я вижу, - это распространение внутренних вызовов методов, что может несколько повлиять на производительность. Я не думаю, что это сильно беспокоит; редко, когда выполнение кода на Python становится узким местом вашей производительности в веб-приложении.

ОБНОВЛЕНИЕ : собственные общие представления Django теперь основаны на классах.

ОБНОВЛЕНИЕ : FWIW, я изменил свое мнение о взглядах на основе классов, так как этот ответ был написан. После интенсивного их использования в нескольких проектах, я чувствую, что они имеют тенденцию приводить к коду, который является достаточно СУХИМЫМ для написания, но очень трудным для чтения и сопровождения позже, потому что функциональность разбросана по очень многим различным местам, а подклассы настолько зависимы на каждой детали реализации суперклассов и миксинов. Теперь я чувствую, что TemplateResponse и декораторы представлений - лучший ответ для разложения кода представления.

13 голосов
/ 27 мая 2010

Мне нужно было использовать представления, основанные на классе, но я хотел иметь возможность использовать полное имя класса в моем 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/)

10 голосов
/ 07 августа 2008

Если вы просто отображаете данные из моделей, почему бы не использовать Django Generic Views ? Они предназначены для того, чтобы вы могли легко отображать данные из модели без необходимости писать собственные представления и рассказывать о сопоставлении параметров URL с представлениями, выборке данных, обработке краевых случаев, выводе рендеринга и т. Д.

3 голосов
/ 26 августа 2008

Вы всегда можете создать класс, переопределить функцию __call__ и затем указать URL-файл на экземпляр класса. Вы можете взглянуть на класс FormWizard , чтобы увидеть, как это делается.

2 голосов
/ 12 августа 2008

Если вы не хотите сделать что-то немного более сложное, использование универсальных представлений - путь. Они гораздо более мощные, чем предполагает их название, и если вы просто отображаете данные модели, универсальные представления сделают эту работу.

2 голосов
/ 03 августа 2008

Похоже, вы пытаетесь объединить вещи, которые не должны быть объединены. Если вам необходимо выполнить различную обработку в вашем представлении, в зависимости от того, на какой объект вы пытаетесь взглянуть: пользователь или группа, вам следует использовать две разные функции представления.

С другой стороны, могут быть общие идиомы, которые вы хотите извлечь из представлений типа object_detail ... возможно, вы могли бы использовать декоратор или просто вспомогательные функции?

* 1005 Дан *

1 голос
/ 08 октября 2014

Вы можете использовать общие виды Django. Вы можете легко получить желаемую функциональность благодаря Django generic Views

1 голос
/ 23 сентября 2008

Обычные представления обычно подходят, но в конечном итоге вы можете обрабатывать URL-адреса по своему усмотрению. FormWizard работает на основе классов, как и некоторые приложения для API RESTful.

По сути, с помощью URL вы получаете кучу переменных и место для обеспечения возможности вызова; то, что вы вызываете, полностью зависит от вас - стандартный способ - предоставить функцию - но в конечном итоге Django не накладывает никаких ограничений на то, что вы делаете .

Я согласен, что еще несколько примеров того, как это сделать, было бы неплохо, хотя FormWizard - это то, с чего стоит начать.

1 голос
/ 26 августа 2008

Если вы хотите поделиться общими функциями между страницами, я предлагаю вам взглянуть на пользовательские теги. Их довольно легко создать , и они очень мощные.

Кроме того, шаблоны могут расширяться от других шаблонов . Это позволяет вам иметь базовый шаблон для настройки макета страницы и делиться этим между другими шаблонами, которые заполняют пробелы. Вы можете вкладывать шаблоны на любую глубину; позволяя указывать макет для отдельных групп связанных страниц в одном месте.

...