6

デフォルトのCherryPyルーティングスタイルは、で装飾されたメソッドを持つクラスのインスタンスに基づいています@cherrypy.expose

以下の例では、これらのURLは、通常のクラスを簡単に調整することで提供されます。

/
/hello
/hello/again
/bye
/bye/again

Flaskの@routeまたは他のデコレータを使用してこれを実現する方法があるのだろうか。

import cherrypy

class Root(object):
    @cherrypy.expose
    def index(self):
        return 'my app'

class Greeting(object):
    def __init__(self, name, greeting):
        self.name = name
        self.greeting = greeting

    @cherrypy.expose
    def index(self):
        return '%s %s!' %(self.greeting, self.name)

    @cherrypy.expose
    def again(self):
        return '%s again, %s!' %(self.greeting, self.name)

if __name__ == '__main__':
    root = Root()
    root.hello = Greeting('Foo', 'Hello')
    root.bye = Greeting('Bar', 'Bye')
    cherrypy.quickstart(root)
4

1 に答える 1

2

このようなことを行うには、Pythonの魔法を少し使用する必要がありますが、フラスコを使用することは絶対に可能です。例をコピーする最も簡単な方法は、flaskをサブクラス化することです。これはそれを行う1つの方法です:

import inspect
from flask import Flask


def expose(f):
    """Decorator that flags a method to be exposed"""
    f._exposed_method = True
    return f


class FlaskOfCherryPy(Flask):
    """Custom flask that allows cherrypy's expose decorator"""
    def quickstart(self, root_handler, *args, **kwargs):
        self._process_root_handler(root_handler)
        self.run(*args, **kwargs)

    def _process_root_handler(self, root_handler):
        # Prime the recursive processing
        root_url = []
        self._process_a_handler(root_handler, root_url)

    def _process_a_handler(self, current_handler, url_stack):
        # This gives a list of all the members of current_handler
        members = inspect.getmembers(current_handler)
        for name, value in members:
            # You probably want to skip things that start with a _ or __
            if name.startswith('_'):
                continue

            # Check if the method is decorated
            is_exposed_method = getattr(value, '_exposed_method', False)

            # If it's a callable with the _exposed_method attribute set
            # Then it's an exposed method
            if is_exposed_method and callable(value):
                self._add_exposed_url(url_stack, name, value)
            else:
                new_stack = url_stack[:]
                new_stack.append(name)
                self._process_a_handler(value, new_stack)

    def _add_exposed_url(self, url_stack, name, view_func):
        copied_stack = url_stack[:]

        if name != 'index':
            copied_stack.append(name)

        url = "/%s" % "/".join(copied_stack)

        if name == 'index':
            copied_stack.append(name)

        view_name = "_".join(copied_stack)
        self.add_url_rule(url, view_name, view_func)


class Root(object):
    @expose
    def index(self):
        return 'my app'


class Greeting(object):
    def __init__(self, name, greeting):
        self.name = name
        self.greeting = greeting

    @expose
    def index(self):
        return '%s %s!' %(self.greeting, self.name)

    @expose
    def again(self):
        return '%s again, %s!' %(self.greeting, self.name)


if __name__ == '__main__':
    root = Root()
    root.hello = Greeting('Foo', 'Hello')
    root.bye = Greeting('Bar', 'Bye')
    app = FlaskOfCherryPy(__name__)
    app.quickstart(root)

基本的に、トリックは、属性でタグ付けされたすべてのメソッドを取得し、 _exposed_methodそれらをに渡すことですFlask.add_url_ruleここのドキュメントを参照してください)。フラスコの美しさは、それを伸ばすのがそれほど怖くないほど軽量なシステムであるということです。自分で飛び込んで試してみることを強くお勧めしますが、質問を解決するのは楽しかったので、ここに要点としてスクリプトを示します。

私が書いたこの特定のコードは完全ではなく、十分にテストされていませんが、特定のユースケースでは間違いなく機能します。また、本番環境でアプリを実行する方法とは限りません。それを行うには、ある種のアプリケーションファクトリを作成する必要があります。繰り返しになりますが、フラスコの内部を調べて、希望どおりの動作をさせることを強くお勧めします。また、flaskが提供するクラスベースのビューまたは青写真を確認することもできます。彼らはあなたがここでそれらを持っていたのと同じようにいくつかのことをすることができます。確かに、それらの使用は非常に異なり、インスタンス属性の設定は、バニラブループリントを使用して可能であると私が知っていることではありません。繰り返しますが、いつでも拡張できます:-)

于 2012-08-21T06:42:24.110 に答える