Django日曜大工パート3:ルート、デバッグ、ミドルウェア、ボトル、ビーカー

パート1
パート2

はじめに


この記事では、wsgiアプリケーションの実装の複雑さに焦点を当てます。 大規模なものは言うまでもなく、すでにこれを行う多くのマイクロフレームがあるため、アプリケーションサーバーをゼロから作成することは検討しません。 これらの目的のためにボトルが選ばれました。 主にそのミニマリズムのため。 また、ビーカーが管理するルート、統計、およびセッションについても説明します。

デバッグ


マイクロフレームの主な問題の1つは、アプリケーションでエラーが発生したときに、wsgiが提供するほとんどのエラーをログに記録する必要があることです。 そして、これらのすべてをブラウザーのページ、または何らかの投稿要求がエラーを返した場合のコンソールで確認したいと思います。

これを行うには、単に処理チェーンに統合し、アプリケーション自体がキャッチしなかったすべての例外をキャッチし、美しくデザインされたページとしてスローします。
try: #  bottle        ,    . @bottle.hook('before_request') def pre_init(): #       , ini_environment() #       #  options_session #   bottle app = bottle.app() app.catchall = False #       . debugger = DebuggerM(app) #     . session = SessionMiddleware(debugger, options_session) #   application    wsgi' application = session except Exception as e: #            #     . exc = sys.exc_info() def error_apps(environ, start_response): start_response('500 INTERNAL SERVER ERROR', [('Content-Type', 'text/html; charset=utf-8')]) return view_error(exc, environ, e) application = error_apps 


ミドルウェアを直接提供するクラス。

 class DebuggerM(object): """       """ __app = None def __init__ (self, app): #      bottle # app-    ,  application     middleware self.__app = app def __call__(self, environ, start_response): try: #      (   ) app_iter = self.__app(environ, start_response) for item in app_iter: #      #          yield item except Exception as e: #         . start_response('500 INTERNAL SERVER ERROR', [('Content-Type', 'text/html; charset=utf-8')]) yield view_error(sys.exc_info(), environ, e) 


エラーを引き起こす関数自体:
 def view_error(exc, environ, e): import cgi, traceback ee = dict(environ) text= '' text='<h1>ERROR "%s"</h1>' % str(e) text+='<style>pre{border:red solid 1px; max-height:240px; overflow:auto;}</style>' text+='<h2>Stack trace</h2><pre>%s</pre>' % ''.join(reversed(traceback.format_exception(*exc))) text+='<h2>Env</h2><pre">%s </pre>' % ' '.join(['%s=%s' %(k, ee[k])for k in ee]) text+='</pre>' return text 


ルートを操作する


デフォルトでは、任意の関数にフックできるデコレーターとしてbootleにすでにルートがあります:
 @route('/hello/:name') def index(name='World'): return '<b>Hello %s</b>' % name 


しかし、比較的小さなプロジェクトには便利です。 そして、この瞬間を拡張して、このタイプのファイルを任意のコンポーネントで作成できるようにします。
 from app1 import * routes = { 'function': ('/hello/', hello, 'GET'), 'function2':('/hello/<_id>', hello_post, 'POST') } 

したがって、その後、どこでも、できればこのコンポーネントでhello関数を呼び出すことができます。 これを行うには、カーネルのコア機能の説明を含むファイルに書き込みます。
 all_routes = {} def union_routes(dir): routes = {} #               . if __builtin__.__import__('routes', globals=globals()): #    module = sys.modules['routes'] #     routes routes.update(module.routes) #     for name in os.listdir(dir): path = os.path.join(dir, name) #       routes.py if os.path.isdir(path) and os.path.isfile(path+'/routes.py'): #           name = 'app.'+path[len(dir)+1:]+'.routes' if __builtin__.__import__(name, globals=globals()): module = sys.modules[name] routes.update(module.routes) return routes def setup_routes(routes): #           bottle        . all_routes.clear() all_routes.update(routes) for name in routes: path, func, method = routes[name] route(path, method=method, name=name)(func) 


ここで、デバッグの最初の部分で残したコメントを、ルートを初期化するための呼び出しに置き換えて、ルートがすぐに接続されるようにします。
 routes = {} #      routes.update(union_routes(lib_path)) #      routes.update(union_routes(app_path)) setup_routes(routes) 

これですべてのルートが完成しました。必要に応じて、デコレーターで関数をラップするか、route.pyファイルで、関数が割り当てられたルートのリストを設定し、必要に応じてラムダを介して必要なパラメーターを渡すことができます
 from app1 import * routes = { 'function2': ('/hello/<_id>', hello_post, 'POST'), 'function3': ('/base/1', lambda: test(True, u''), 'GET') } 

また、この場合の辞書ルートのキー「function2」を使用すると、リンク自体にどのパラメーターが渡されるかを正確に知ることなく、ルートの名前でリンクを形成できます。たとえば、「/ hello / <_id>」を取得すると、<_ id>が動的に設定されます
 def make_link(name, params, full=False): """     <>     """ #     templ_link = all_routes[name][0][1:] #      <> r = re.compile(r'<([^:>]+)(:[^>]+)?>') #       ,       . while True: rs = r.search(templ_link) if not rs: break sub = rs.group(0) name = rs.group(1) templ_link = re.sub(sub, params[name], teml_link) link = os.path.sep+ templ_link #        ,     . if full: link = 'http://'+get_name_host()+link return link 

ここで、テンプレート内またはコード内のどこかに記述します
 link = make_link('test', {'id':id, 'doc_id':doc_id}, True) 

多くの場合、リンクだけを記述する方が簡単ですが、この機能なしではできない場合もあります。


セッションを操作する


セッションの操作は、ビーカーを使用することです。 この素晴らしいモジュールはセッションで動作し、選択したフォルダーまたはデータベースに保存できます。 たとえば、postgresqlまたはmemcachedに保存するように構成できます。 最初に行うことはインポートです:
 from beaker.middleware import SessionMiddleware 

次に、ルートが初期化された直後に初期化コメントを置き換えます。
  options_session = { 'session.cookie_expires': 30000, 'session.timeout': 30000, 'session.type': 'file', #     'session.data_dir': './s_data' #      } 

そして、pre_init()関数で、いわばセッションを保存する必要があるドメインの定義を動的な行に追加します。
 session.options['session.cookie_domain'] = get_name_host() 

get_name_host()-サイトの名前の取得に従事しています。
その後、必要なのは、セッションを使用できる単純な関数だけです。
 def session(): #    s = request.environ.get('beaker.session') return s 

今どこでも:
 s = session() s['test'] = '123' s.save() 


静力学


ボトルも静力学に従事し、順番に、ニーズに合わせてその能力を拡張します。

 #  bottle          ,           . @route('/static/<component>/<fname:re:.*>') def st_file(component, fname): #              ,     bottle path = os.path.join( settings.lib_path, component, 'static') + os.path.sep if not os.path.exists(path + fname): path = os.path.join( settings.lib_path, 'app', component,'static')+ os.path.sep if not os.path.exists( path + fname): path = os.path.join( os.getcwd(), 'app', component, 'static')+ os.path.sep if not os.path.exists(path + fname) and component == 'static': path = os.path.join( os.getcwd(), 'static')+ os.path.sep return static_file(fname, root=path) 


そのようなモジュールが存在する場合、モジュールスクリプトから必要に応じて静的変数を接続する方法を学習する必要がありますが、メインテンプレートにすべてが無差別に存在するわけではありません。
 def add_resourse(name, append=True): env = get_environment(); t = '' if name.endswith('.css'): t = 'css' if name.endswith('.js'): t = 'js' if not t: return if not name in env['res_list'][t]: if append: env['res_list'][t].append(name) else: env['res_list'][t].prepend(name) 


任意のモジュールでこの関数を呼び出し、このタイプの静的ファイルに正しいパスを渡します '/ static / <component> / <fname:re :. *>'最初の引数として:
 add_resourse(/static/base/base.js, True) 


また、メインテンプレートでは、単に次のように呼び出します。
 {% for res in env.res_list['js'] %} <script type="text/javascript" src="{{res}}"></script> {% endfor %} {% for res in env.res_list['css'] %} <link rel="stylesheet" type="text/css" href="{{res}}" /> {% endfor %} 


ハローワールド


これで、単純なHello Worldは次のようになります。
プロジェクトの/ app / app_oneにroute.pyルートを含むファイルを配置します。
 from app.app_one.view import * routes = { 'hello': ('/', hello, 'GET') } 

view.pyファイルを近くに配置しますが、ここでの名前はロジックの観点を除いて重要ではなくなりました。
 def hello(): text = 'It works' return templ('hello', text=text) 

そして、/ templフォルダーの同じディレクトリに、hello.tplというテンプレートを配置します。
 {{text}} 

私たちは皆、サイトのルートに行き、挨拶を見ます。

まとめ


実際にメインフレームの準備ができました。 一般に、ある程度のフレームワークの中には、この一連のレッスンで検討したものを実装するものがあります。 しかし、どのようにこれを実装することができるかのオプションの1つを見るのは面白いと私には思えます。 次のパートでは、管理パネルの作成とデータの表示について説明します。
今のところすべてです。 すべて成功。

使用済みの有用な材料


びん
ビーカーとキャッシング
ビーカー
PythonのWebの概要
Python Webサーバーゲートウェイインターフェイス

Source: https://habr.com/ru/post/J148261/


All Articles