Классовые представления в Джанго

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

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

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

3.08.2008 15:55:28
9 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

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

41
15.11.2011 20:39:59
Выполнение Python не является узким местом, но может повлиять на масштабируемость сайта и общую производительность. Я так рад, что memcache существует!
StefanNch 23.12.2012 12:06:46

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

12
31.05.2010 15:54:36

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

10
12.07.2013 19:06:48

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

3
15.11.2011 20:41:16
Процессор разметки съел ваши __. Используйте \ _, чтобы скрыть разметку. Метод класса __call__ - это то, что вызывается. Проблема заключается в том, чтобы убедиться, что в urls.py есть экземпляр класса, доступного для него. Это делает ваш urls.py несколько более сложным.
S.Lott 17.09.2008 02:07:54

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

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

Дан

2
3.08.2008 17:40:25

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

2
11.08.2008 22:59:42

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

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

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

1
23.09.2008 19:05:51

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

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

1
12.07.2013 19:05:51
Я не думаю, что помещать слишком много логики в шаблон - это хорошая идея.
Attila O. 17.09.2010 11:48:39

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

1
8.10.2014 05:53:09