LoginSignup
2
3

More than 5 years have passed since last update.

Django channelsでルーティングをDjango風に2つに分ける

Posted at

Djangoでこまごまとしたappをいっぱい書いているとDjangoのルーティングの仕方が書きやすくていいなーと思ってて
ちょろっとchannels触ってみたら違うやり方でルートに置いたrouting.pyに全部直書きっぽくて、うーんとなったので書きやすいように書いてみた

環境

いらないものは省略してます

$  tree -L 2                                                                                                                                      
.
├── db.sqlite3
├── app1
│   ├── consumers.py    <-- これは後半に追加する
│   ├── routing.py
│   ├── urls.py
│   └── views.py
├── manage.py
└── project
    ├── consumers.py
    ├── routing.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

理想

project/routing.pyにappごとのルーティングを記述
app1/routing.pyに細かいルーティングを記述
できるだけDjangoっぽく書きたい

見てみる

まず普通の書き方

project/routing.py

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter([
            path('ws/app1/<val>/', app1.consumers.MyConsumer, name='ws_app1'),
        ])
    ),
})

このpathをincludeにはしてみたけどだめっぽい。

最終的にURLRouteにpathが入ったlistが行けば解決しそう。

ちょっと書いてみる

app1/routing.pyを作る。いつもどおりに書いてみる

app1/routing.py
urlpatterns = [
    path('<val>/', consumers.MyConsumer, name='ws_app1'),
]

これでproject/routing.pyinclude('ws/app1', ~~)的なことがしたい。

pathに先頭のパスを追加できないかな・・・

shell
>> from django.urls import path
>> from app1 import consumers
>> 
>> a = path('<val>/', consumers.MyConsumer)
>> a
<URLPattern '<val>/'>
>> a.pattern
<django.urls.resolvers.RoutePattern object at 0x7fdad25a00f0>
>> a.pattern.regex
re.compile('^(?P<val>[^/]+)/$')

うーん、この時点でパスの表記が正規表現に落とし込んであるみたいなので追加するのはダルそう。取り出すのも

app1/routing.pyの方はpathのリストじゃなくて必要事項のタプルとかにするか。

app1/routing.py
urlpatterns = [
    ('<val>/', consumers.ChatConsumer, 'ws_app1'),
]

また見てみる

pathは中で何してるのかな
上のを見る通りURLPatternオブジェクトを返してますね。これのリストを作ればいいっぽい。

そーす
    pattern = Pattern(route, name=name, is_endpoint=True)
    return URLPattern(pattern, view, kwargs, name)

これをやればいい

  • importがかさまないようにもとのincludeと同じように文字列で受け取る(モジュールが来ても対応してる)
  • パターンのlistの名前はurlpatternsにする(変更できる)
  • リストを最終的につなぐのでitertools.chainを使う
project/routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls.resolvers import URLPattern, RoutePattern
from itertools import chain
from importlib import import_module

def include_(path: str, routing: str, pattern_list_name: str = 'urlpatterns'):
    if isinstance(routing, str):
        routing = import_module(routing)
    urlpatterns = getattr(routing, pattern_list_name)
    return [URLPattern(RoutePattern(path+i[0], i[2], True), i[1], None, i[2]) for i in urlpatterns]


application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(list(chain(
            include_('ws/app1/', 'app1.routing'),
        )))
    ),
})

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3