LoginSignup
0
0

More than 3 years have passed since last update.

python url設定 include 関数に関して

Last updated at Posted at 2020-10-18

URLの設定でinclude は実際何してるんだろう?

include()を使用してPATHの設定を引きとれるとなっているが、実際何をしているんだろう

(参考)
mysite/urls.py

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

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

実際の関数内原文

def include(arg, namespace=None):
    app_name = None
    if isinstance(arg, tuple):
        try:
            urlconf_module, app_name = arg
        except ValueError:
            if namespace:
                raise ImproperlyConfigured(
                    'Cannot override the namespace for a dynamic module that '
                    'provides a namespace.'
                )
            raise ImproperlyConfigured(
                'Passing a %d-tuple to include() is not supported. Pass a '
                '2-tuple containing the list of patterns and app_name, and '
                'provide the namespace argument to include() instead.' % len(arg)
            )
    else:
        urlconf_module = arg

    if isinstance(urlconf_module, str):
        urlconf_module = import_module(urlconf_module)
    patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)
    app_name = getattr(urlconf_module, 'app_name', app_name)
    if namespace and not app_name:
        raise ImproperlyConfigured(
            'Specifying a namespace in include() without providing an app_name '
            'is not supported. Set the app_name attribute in the included '
            'module, or pass a 2-tuple containing the list of patterns and '
            'app_name instead.',
        )
    namespace = namespace or app_name
    if isinstance(patterns, (list, tuple)):
        for url_pattern in patterns:
            pattern = getattr(url_pattern, 'pattern', None)
            if isinstance(pattern, LocalePrefixPattern):
                raise ImproperlyConfigured(
                    'Using i18n_patterns in an included URLconf is not allowed.'
                )
    return (urlconf_module, app_name, namespace)

ここから調べた結果

def include(arg, namespace=None):

arg は必須 namespace は任意

if isinstance(arg, tuple):

arg が tuple型(配列)かチェックしている (isinstance関数)

urlconf_module, app_name = arg

arg = ('a','b') の場合
urlconf_module ='a'
app_name = 'b' となる
arg = ('a','b','c') の場合はエラーになる
エラーの場合は例外で返る

このことにより

arg = 'hoge'
  or
arg = ('hoge','fuga')

が通過できるようになるということがわかる

    if isinstance(urlconf_module, str):
        urlconf_module = import_module(urlconf_module)

urlconf_module が文字列かどうかチェックしている
文字列の場合 import_module の関数を実行している


呼び出されている import_module について

/AppData/Local/Programs/Python/Python38/Lib/importlib/__init__.py

def import_module(name, package=None):
    level = 0
    if name.startswith('.'): 
        if not package:
            msg = ("the 'package' argument is required to perform a relative "
                   "import for {!r}")
            raise TypeError(msg.format(name))
        for character in name:
            if character != '.':
                break
            level += 1
    return _bootstrap._gcd_import(name[level:], package, level)

import moduleに関する調査

if name.startswith('.'):

文字列の最初が'.'で始まっているか調べる startswith

if not package:

ここはtrueが返ってくる?
ならエラーで終わるやん。

 for character in name:
    if character != '.':
        break
    level += 1

ここでは、最初の'.'以外の文字が出るまで繰り返す。
「../test」なら「/test」になる様子

しかし、ここではlavel=0以外はかんがえられない

return _bootstrap._gcd_import(name[level:], package, level)

name[level:] nameの文字列
package は None
level は 0

※name[level:] は
name[0:] と同じで文字列の切り出しです。
name[最初の文字位置:最後の文字位置] という意味
数字が入っていないと必然的に一番最初・一番最後という意味になる。


呼び出されている _bootstrap._gcd_import について

C:\Users\(ユーザー名)\AppData\Local\Programs\Python\Python38\Lib\importlib\_bootstrap.py

def _gcd_import(name, package=None, level=0):
    _sanity_check(name, package, level)
    if level > 0:
        name = _resolve_name(name, package, level)
    return _find_and_load(name, _gcd_import)

level は0しかありえないので必然的に return _find_and_load (name, _gcd_import)
name はそのまま引き継がれ、
_gcd_import は実行された関数が含まれている

関数を引数に入れる発想がなかった!


呼び出されている _find_and_loadについて

C:\Users\(ユーザー名)\AppData\Local\Programs\Python\Python38\Lib\importlib\_bootstrap.py

def _find_and_load(name, import_):
    """Find and load the module."""
    with _ModuleLockManager(name):
        module = sys.modules.get(name, _NEEDS_LOADING)
        if module is _NEEDS_LOADING:
            return _find_and_load_unlocked(name, import_)

    if module is None:
        message = ('import of {} halted; '
                   'None in sys.modules'.format(name))
        raise ModuleNotFoundError(message, name=name)

    _lock_unlock_module(name)
    return module
0
0
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
0
0