LoginSignup
21

More than 5 years have passed since last update.

djangoのurl, pathについて

Last updated at Posted at 2018-07-06

Django初心者です。

Django2系を書いていると、urls.pyに出てくる

urls.py
The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""

が気になって、少し調べてみました。

Django1系ではどう書くか

djangoのチュートリアルとかをやると、urls.pyには

urls.py
from django.contrib import admin
from django.conf.urls import url, include

urlpatterns = [
   url('', include('myapp.urls'))
   url(r'^admin/', admin.site.urls),
]

みたいに書くことがあると思います。
urlpatternで、adminとかmyapp.urlsで指定されているテンプレートを展開する処理です。

Django2系では

urls.py
from django.contrib import admin
from django.urls import path, include, re_path

urlpatterns = [
   path('', include('myapp.urls'))
   re_path(r'admin/', admin.site.urls),
]

という感じかけるようになっています。

Django 2.0 release notesによると

Simplified URL routing syntax¶
The new django.urls.path() function allows a simpler, more readable URL routing syntax. For example, this example from previous Django releases:

url(r'^articles/(?P[0-9]{4})/$', views.year_archive),
could be written as:

path('articles/int:year/', views.year_archive),
The new syntax supports type coercion of URL parameters. In the example, the view will receive the year keyword argument as an integer rather than as a string. Also, the URLs that will match are slightly less constrained in the rewritten example. For example, the year 10000 will now match since the year integers aren’t constrained to be exactly four digits long as they are in the regular expression.

The django.conf.urls.url() function from previous versions is now available as django.urls.re_path(). The old location remains for backwards compatibility, without an imminent deprecation. The old django.conf.urls.include() function is now importable from django.urls so you can use from django.urls import include, path, re_path in your URLconfs.

The URL dispatcher document is rewritten to feature the new syntax and provide more details.

とのことです。ざっくりと和訳すると

  • もっとシンプルで、読みやすいurlルーティングを作った。
  • pathは型強制(Type Hintsみたいなものかな)をサポートしている
  • 昔のやつは後方互換性のために残していて、すぐに消したりはしない
  • django.conf.urls.url() == django.urls.re_path()
  • includeもdjango.urlsに入っている

って感じみたいです。

中身は?

githubのdjangoをみて見ると、すでにdjango.conf.urlsのurlはre_pathに置き換わっていました。

じゃあ、pathとre_pathの違いはなんだろう?
djangoのconf.py, resolver.pyをみてみます

django/conf.py
path = partial(_path, Pattern=RoutePattern) 
re_path = partial(_path, Pattern=RegexPattern) 

Patternの違いっぽいですね。最終的に、_pathはURLResolverを返すので、その辺をみて見ると、冒頭にmatchメソッドが使われています。
簡単に、matchメソッドで比べて見ると、

RoutePattern
    def __init__(self, route, ...):
        ...
        self.converters = _route_to_regex(str(route), is_endpoint)[1]

    def match(self, path):
        match = self.regex.search(path)
        if match:
            # RoutePattern doesn't allow non-named groups so args are ignored.
            kwargs = match.groupdict()
            for key, value in kwargs.items():
                converter = self.converters[key]
                try:
                    kwargs[key] = converter.to_python(value)
                except ValueError:
                    return None
            return path[match.end():], (), kwargs
        return None

RoutePatternはurlpatternを渡して、正規表現に一度変換して、UUIDに戻して返す

RegexPattern
    def match(self, path):
        match = self.regex.search(path)
        if match:
            # RoutePattern doesn't allow non-named groups so args are ignored.
            kwargs = match.groupdict()
            for key, value in kwargs.items():
                converter = self.converters[key]
                try:
                    kwargs[key] = converter.to_python(value)
                except ValueError:
                    return None
            return path[match.end():], (), kwargs
        return None

RegexPatternは、渡した正規表現でマッチングして返すみたいな感じの実装になっているのかな?
※やや頭が混乱してきました。

まとめ

あんまり私はこの辺詳しくないので、大したことは言えませんがpath, re_pathどちらで渡しても結局正規表現でマッチングしてくれるようです。
なので、僕はpathの方が楽だしそっちを使おうかなあ、とか思っています
もっと詳しい方色々教えてください

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
21