Каковы некоторые рекомендации по структурированию приложений cherrypy? - PullRequest
5 голосов
/ 18 апреля 2010

Я пишу приложение cherrypy, и мне было интересно, как лучше структурировать мои обработчики и код для больших приложений?

Я понимаю, что назначение - это просто через cherrypy.root, но каковы методы написания обработчиков и их назначения?

(Позвольте мне доказать мою путаницу!) Моя первоначальная мысль - написать стандартный класс-обработчик, который выведет шаблон для запуска на основе текущего URL-адреса или комбинации класса / метода. Затем я бы назначил один экземпляр этого обработчика несколько раз пути для создания страниц. Однако я не вижу, как это работает, поскольку рекурсивные ссылки не будут работать правильно.

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

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

Ответы [ 2 ]

10 голосов
/ 19 апреля 2010

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

Однако предпочтительный подход отличается. Для большинства веб-приложений вы на самом деле не хотите изменять фактическую логику построения ваших обработчиков, а также не заботитесь о переменных или методах уровня класса; вместо этого вы хотите повторно использовать переменные и методы для каждого URI или для поддерева URI или для сайта, а не для класса. Вы склонны отличать один набор обработчиков от другого набора больше конфигурацией экземпляра (метаданные обработчика) и методами экземпляра (логика обработчика). Традиционное наследование на основе классов может сделать это, но это немного тупой инструмент для такой настройки.

Таким образом, CherryPy разработан для предоставления такого рода настройки для каждого набора ресурсов, которую наследование на основе классов не дает. Это обеспечивается посредством 1) разработки системы конфигурации, которая позволяет связывать метаданные с одним URI, поддеревом URI, поддеревом обработчиков или целым сайтом с одинаковым синтаксисом (см. http://docs.cherrypy.org/dev/intro/concepts/config.html для обзора) и 2) система перехватов и инструментов, которая позволяет связать логика с одним URI, поддеревом URI, поддеревом обработчиков или целым сайт. Смотри http://docs.cherrypy.org/dev/intro/concepts/tools.html

Итак, практически: используйте обычные атрибуты на cherrypy.root для построения вашего дерева обработчиков:

def make_app():
    root = Root()
    root.foo = Foo()
    root.bars = BarCollection()
    return root

Однако не заставляйте Root, Foo и Bar наследовать от общего базового класса. Вместо этого, пишите независимые Инструменты, чтобы делать такие вещи, как «выводить шаблоны». То есть вместо:

from cherrypy import expose

class Foo(MyAppBase):
    @expose()
    def index(self, a, b, c):
        ...

root.foo = Foo(template='foo.html')

запись:

from cherrypy import expose, tools

class Foo(object):
    @tools.render(template='foo.html')
    @expose()
    def index(self, a, b, c):
        ...

root.foo = Foo()

... где 'tools.render' - инструмент CherryPy, который вы написали для поиска и применения данного шаблона. Этот подход позволит вам переопределить аргументы инструмента в вашем конфигурационном файле и избежать переупаковки или исправления вашего кода:

[/foo/]
tools.render.template = 'foo2.html'
5 голосов
/ 19 апреля 2010

Этот вопрос дико субъективен, но я попробую.

  • Прежде всего, всегда держите базу данных и код данных отдельно от веб-кода. Что я делаю, так это большое количество маленьких файлов с одним классом в папке DB/, которые все объединены в файл Base.py, например:

    Web/
        Base.py - The main "base" class, which includes the classes in other 
                  web files, starts the web server in __init__
        Users.py - The class which includes methods generally from "DB/Users.py" 
                   which checks permissions etc before returning (you may 
                   wish to add DB-level security later though)
        ...
    DB/
        Base.py - The main base DB class, includes the other DB classes. Creates 
                  new SQLAlchemy/whatever instances and create database schemas if 
                  they don't etc. May pay to have database-wide methods
                  here to keep creating connections etc in one place if you 
                  decide to change databases later 
        Users.py - The user/password etc DB storage class file
        ...
    Templates/
        (HTML templates go here)
    Static/
        (Static images/CSS/javscript etc go here)
    
    Не забывайте, конечно, __init__.py в каждом каталоге модулей, чтобы python мог найти модули в подкаталогах
  • На мой взгляд, не всегда важно, какие методы вы используете для структурирования кода, но будьте последовательны. Я пишу документ со всеми моими соглашениями с обоснованием их использования и стараюсь следовать им до того момента, когда это имеет смысл, но, как всегда a foolish consistency is the hobgoblin of small minds, как цитирование документов в стиле Python : )

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

  • Этот, вероятно, спорный - я обычно называю свои классы Class и просто ссылаюсь на него по имени модуля. Я приведу пример Base.py:
    import Users
    class Base(Users.Class):
        def <code>__init__</code>(self):
            Users.Class.<code>__init__</code>(self)
    
    Это помогает уменьшить проблемы, когда другие модули ссылаются друг на друга при импорте, так как from Users import Users будет конфликтовать, если Users.py имеет from Base import x, поэтому я всегда ссылаюсь по имени модуля. Это всего лишь личное предпочтение, поэтому делай, что хочешь: -P

Надеюсь, вы получите идею из этого поста.

...