如何在Django中列出urlpatterns(端点)?

231

我该如何查看“reverse”正在查找的当前urlpatterns?

我在视图中调用带有参数的反向函数,但是它却不能正常工作。有没有办法检查哪些内容存在以及为什么我的模式不起作用?


https://dev59.com/MnI-5IYBdhLWcg3wfoa1 - pmav99
2
打开DEBUG模式并查看调试输出中的URL列表? - boatcoder
21个回答

306

如果您想获取项目中所有URL的列表,首先需要安装django-extensions。

您可以使用命令进行简单安装。

pip install django-extensions

有关软件包的更多信息,请访问django-extensions

之后,在您的settings.py文件中像这样添加django_extensionsINSTALLED_APPS

INSTALLED_APPS = (
...
'django_extensions',
...
)

urls.py 示例:

from django.urls import path, include
from . import views
from . import health_views

urlpatterns = [
    path('get_url_info', views.get_url_func),
    path('health', health_views.service_health_check),
    path('service-session/status', views.service_session_status)
]

然后,在终端中运行任何命令

python manage.py show_urls
或者
./manage.py show_urls

基于配置文件urls.py的示例输出:

/get_url_info             django_app.views.get_url_func
/health                   django_app.health_views.service_health_check
/service-session/status   django_app.views.service_session_status

你可以通过查看文档来获取更多信息。


4
实际上,我错了,这个功能 Django 并没有提供。 - robert
我从中得到的只有 TypeError: unsupported operand type(s) for +: 'NoneType' and 'str' - Paul Tomblin
7
请在安装后将 django_extensions 添加到您的 INSTALLED_APPS 中。 - Owen

118

试试这个:

from django.urls import get_resolver
get_resolver().reverse_dict.keys()

如果你仍在使用Django 1.*:

from django.core.urlresolvers import get_resolver
get_resolver(None).reverse_dict.keys()

14
这将返回视图函数,而不是URL。 - Ronen Ness
5
要让它返回URL,请改为执行以下操作:set(v[1] for k,v in get_resolver(None).reverse_dict.iteritems()) - kloddant
18
对于Python 3,可以使用以下代码:set(v[1] for k,v in get_resolver(None).reverse_dict.items())。该代码用于获取所有反向DNS解析列表中的IP地址,并将其转换为一个集合对象。 - Private
7
django.core.urlresolvers 在 Django 2.0 中已被移除,替换导入语句为 from django.urls import get_resolver。请注意,翻译过程中应保持原意不变,并使内容易于理解。 - hoefling
3
对我来说,这不再有效了,只返回项目中的一小部分网址。 - J__

90

Django >= 2.0 解决方案

我测试了此帖中的其他答案,它们要么无法与Django 2.X一起使用,要么不完整,要么太复杂。因此,这是我的解决方案:

from django.conf import settings
from django.urls import URLPattern, URLResolver

urlconf = __import__(settings.ROOT_URLCONF, {}, {}, [''])

def list_urls(lis, acc=None):
    if acc is None:
        acc = []
    if not lis:
        return
    l = lis[0]
    if isinstance(l, URLPattern):
        yield acc + [str(l.pattern)]
    elif isinstance(l, URLResolver):
        yield from list_urls(l.url_patterns, acc + [str(l.pattern)])
    yield from list_urls(lis[1:], acc)

for p in list_urls(urlconf.urlpatterns):
    print(''.join(p))

这段代码会打印出所有的URL,与其他一些解决方案不同的是它会打印出完整路径而不仅仅是最后一个节点。例如:

admin/
admin/login/
admin/logout/
admin/password_change/
admin/password_change/done/
admin/jsi18n/
admin/r/<int:content_type_id>/<path:object_id>/
admin/auth/group/
admin/auth/group/add/
admin/auth/group/autocomplete/
admin/auth/group/<path:object_id>/history/
admin/auth/group/<path:object_id>/delete/
admin/auth/group/<path:object_id>/change/
admin/auth/group/<path:object_id>/
admin/auth/user/<id>/password/
admin/auth/user/
... etc, etc

1
我想获取视图的URL和名称,该怎么做?因为我想要像你的结果那样获取视图的名称和模式。请问怎么做? - Mbambadev
@NathanIngram 视图存储在URLPattern对象的“回调”属性中,因此您可以将yield acc + [str(l.pattern)]行更改为yield acc + [str(l.pattern)], l.callback。请记住,它将返回视图函数本身而不是名称。 - Cesar Canassa
我收到了错误信息:--->>>> TypeError: 序列中的第0项应为str实例,但发现是list。 - Mbambadev
@NathanIngram "print(''.join(p))"无法工作,因为现在它是一个元组列表而不是字符串列表,请尝试使用"print(''.join(p[0]))"。 - Cesar Canassa
1
尾递归的绝佳示例 :) 顺便说一句 - 如果有人想要获取视图类,只需将 yield acc + [str(l.pattern)] 更改为 yield [l.callback.view_class] - WBAR

29

Django 1.11,Python 2.7.6

切换到你的Django项目目录

运行命令:python manage.py shell

然后粘贴以下代码。

from django.conf.urls import RegexURLPattern, RegexURLResolver
from django.core import urlresolvers
urls = urlresolvers.get_resolver()

def if_none(value):
    if value:
        return value
    return ''

def print_urls(urls, parent_pattern=None):
    for url in urls.url_patterns:
        if isinstance(url, RegexURLResolver):
            print_urls(url, if_none(parent_pattern) + url.regex.pattern)
        elif isinstance(url, RegexURLPattern):
            print(if_none(parent_pattern) + url.regex.pattern)

print_urls(urls)

样例输出:

^django-admin/^$
^django-admin/^login/$
^django-admin/^logout/$
^django-admin/^password_change/$
^django-admin/^password_change/done/$
^django-admin/^jsi18n/$
^django-admin/^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$
^django-admin/^wagtailimages/image/^$
^django-admin/^wagtailimages/image/^add/$
^django-admin/^wagtailimages/image/^(.+)/history/$
^django-admin/^wagtailimages/image/^(.+)/delete/$
^django-admin/^wagtailimages/image/^(.+)/change/$
^django-admin/^wagtailimages/image/^(.+)/$
...

这是对我有效的答案,尽管我不得不在urls = urlresolvers.get_resolver(None)这一行中添加了None,有时候在一些URL的开头会出现'None'。 - Chris

24
这里有一个快速而简单的技巧,可以让你获取所需的信息,而无需修改任何设置。
pip install django-extensions
python manage.py shell -c 'from django.core.management import call_command; from django_extensions.management.commands.show_urls import Command; call_command(Command())'

这是在@robert的回答的基础上进行的。虽然正确,但我不想把django-extensions作为依赖项,即使只是一秒钟。

Django-extensions 作为依赖有什么问题吗? - AlxVallejo
@AlxVallejo 绝对没有问题!这是一个非常好的、维护良好的模块,但如果你每5个月才使用它,因为你只需要列出你的URL(我的情况)...我的解决方案可能正是你需要的。如果你每天都依赖它,请务必安装它! - Javier Buzzi

24

在Django 3.0中,它就像这样简单:

from django.urls import get_resolver
print(get_resolver().url_patterns)

打印结果:[<URLPattern '' [name='home']>, <URLPattern '/testing' [name='another_url']>]


2
在我的情况下不起作用,只打印一个API网址: [<URLResolver <URLPattern list> (None:None) 'api/v1/'>,<URLPattern'^$'>,<URLPattern'^media/(?P<path>.*)$'>] - Vedmant
2
很不错,但是有没有一种方法可以进入管理URL模式内部? - Bobort

17

我正在使用以下命令:

(Python3 + Django 1.10)

from django.core.management import BaseCommand
from django.conf.urls import RegexURLPattern, RegexURLResolver
from django.core import urlresolvers


class Command(BaseCommand):

    def add_arguments(self, parser):

        pass

    def handle(self, *args, **kwargs):

        urls = urlresolvers.get_resolver()
        all_urls = list()

        def func_for_sorting(i):
            if i.name is None:
                i.name = ''
            return i.name

        def show_urls(urls):
            for url in urls.url_patterns:
                if isinstance(url, RegexURLResolver):
                    show_urls(url)
                elif isinstance(url, RegexURLPattern):
                    all_urls.append(url)
        show_urls(urls)

        all_urls.sort(key=func_for_sorting, reverse=False)

        print('-' * 100)
        for url in all_urls:
            print('| {0.regex.pattern:20} | {0.name:20} | {0.lookup_str:20} | {0.default_args} |'.format(url))
        print('-' * 100)

用法:

./manage.py showurls

输出样例:

----------------------------------------------------------------------------------------------------
| ^(.+)/$              |                      | django.views.generic.base.RedirectView | {} |
| ^(.+)/$              |                      | django.views.generic.base.RedirectView | {} |
| ^(.+)/$              |                      | django.views.generic.base.RedirectView | {} |
| ^(.+)/$              |                      | django.views.generic.base.RedirectView | {} |
| ^(.+)/$              |                      | django.views.generic.base.RedirectView | {} |
| ^(.+)/$              |                      | django.views.generic.base.RedirectView | {} |
| ^static\/(?P<path>.*)$ |                      | django.contrib.staticfiles.views.serve | {} |
| ^media\/(?P<path>.*)$ |                      | django.views.static.serve | {'document_root': '/home/wlysenko/.virtualenvs/programmerHelper/project/media'} |
| ^(?P<app_label>polls|snippets|questions)/$ | app_list             | apps.core.admin.AdminSite.app_index | {} |
| ^(?P<app_label>activity|articles|badges|books|comments|flavours|forum|marks|newsletters|notifications|opinions|polls|questions|replies|snippets|solutions|tags|testing|users|utilities|visits)/reports/$ | app_reports          | apps.core.admin.AdminSite.reports_view | {} |
| ^(?P<app_label>activity|articles|badges|books|comments|flavours|forum|marks|newsletters|notifications|opinions|polls|questions|replies|snippets|solutions|tags|testing|users|utilities|visits)/statistics/$ | app_statistics       | apps.core.admin.AdminSite.statistics_view | {} |
| articles/(?P<slug>[-\w]+)/$ | article              | apps.articles.views.ArticleDetailView | {} |
| book/(?P<slug>[-_\w]+)/$ | book                 | apps.books.views.BookDetailView | {} |
| category/(?P<slug>[-_\w]+)/$ | category             | apps.utilities.views.CategoryDetailView | {} |
| create/$             | create               | apps.users.views.UserDetailView | {} |
| delete/$             | delete               | apps.users.views.UserDetailView | {} |
| detail/(?P<email>\w+@[-_\w]+.\w+)/$ | detail               | apps.users.views.UserDetailView | {} |
| snippet/(?P<slug>[-_\w]+)/$ | detail               | apps.snippets.views.SnippetDetailView | {} |
| (?P<contenttype_model_pk>\d+)/(?P<pks_separated_commas>[-,\w]*)/$ | export               | apps.export_import_models.views.ExportTemplateView | {} |
| download_preview/$   | export_preview_download | apps.export_import_models.views.ExportPreviewDownloadView | {} |
| ^$                   | import               | apps.export_import_models.views.ImportTemplateView | {} |
| result/$             | import_result        | apps.export_import_models.views.ImportResultTemplateView | {} |
| ^$                   | index                | django.contrib.admin.sites.AdminSite.index | {} |
| ^$                   | index                | apps.core.views.IndexView | {} |
| ^jsi18n/$            | javascript-catalog   | django.views.i18n.javascript_catalog | {'packages': ('your.app.package',)} |
| ^jsi18n/$            | jsi18n               | django.contrib.admin.sites.AdminSite.i18n_javascript | {} |
| level/(?P<slug>[-_\w]+)/$ | level                | apps.users.views.UserDetailView | {} |
| ^login/$             | login                | django.contrib.admin.sites.AdminSite.login | {} |
| ^logout/$            | logout               | django.contrib.admin.sites.AdminSite.logout | {} |
| newsletter/(?P<slug>[_\w]+)/$ | newsletter           | apps.newsletters.views.NewsletterDetailView | {} |
| newsletters/$        | newsletters          | apps.newsletters.views.NewslettersListView | {} |
| notification/(?P<account_email>[-\w]+@[-\w]+.\w+)/$ | notification         | apps.notifications.views.NotificationDetailView | {} |
| ^password_change/$   | password_change      | django.contrib.admin.sites.AdminSite.password_change | {} |
| ^password_change/done/$ | password_change_done | django.contrib.admin.sites.AdminSite.password_change_done | {} |
| ^image/(?P<height>\d+)x(?P<width>\d+)/$ | placeholder          | apps.core.views.PlaceholderView | {} |
| poll/(?P<pk>\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/(?P<slug>[-\w]+)/$ | poll                 | apps.polls.views.PollDetailView | {} |
| ^add/$               | polls_choice_add     | django.contrib.admin.options.ModelAdmin.add_view | {} |
| ^(.+)/change/$       | polls_choice_change  | django.contrib.admin.options.ModelAdmin.change_view | {} |
| ^$                   | polls_choice_changelist | django.contrib.admin.options.ModelAdmin.changelist_view | {} |
| ^(.+)/delete/$       | polls_choice_delete  | django.contrib.admin.options.ModelAdmin.delete_view | {} |
| ^(.+)/history/$      | polls_choice_history | django.contrib.admin.options.ModelAdmin.history_view | {} |
| ^add/$               | polls_poll_add       | django.contrib.admin.options.ModelAdmin.add_view | {} |
| ^(.+)/change/$       | polls_poll_change    | django.contrib.admin.options.ModelAdmin.change_view | {} |
| ^$                   | polls_poll_changelist | django.contrib.admin.options.ModelAdmin.changelist_view | {} |
| ^(.+)/delete/$       | polls_poll_delete    | django.contrib.admin.options.ModelAdmin.delete_view | {} |
| ^(.+)/history/$      | polls_poll_history   | django.contrib.admin.options.ModelAdmin.history_view | {} |
| ^$                   | polls_vote_changelist | django.contrib.admin.options.ModelAdmin.changelist_view | {} |
| publisher/(?P<slug>[-_\w]+)/$ | publisher            | apps.books.views.PublisherDetailView | {} |
| question/(?P<slug>[-_\w]+)/$ | question             | apps.questions.views.QuestionDetailView | {} |
| ^add/$               | questions_answer_add | django.contrib.admin.options.ModelAdmin.add_view | {} |
| ^(.+)/change/$       | questions_answer_change | django.contrib.admin.options.ModelAdmin.change_view | {} |
| ^$                   | questions_answer_changelist | django.contrib.admin.options.ModelAdmin.changelist_view | {} |
| ^(.+)/delete/$       | questions_answer_delete | django.contrib.admin.options.ModelAdmin.delete_view | {} |
| ^(.+)/history/$      | questions_answer_history | django.contrib.admin.options.ModelAdmin.history_view | {} |
| ^add/$               | questions_question_add | django.contrib.admin.options.ModelAdmin.add_view | {} |
| ^(.+)/change/$       | questions_question_change | django.contrib.admin.options.ModelAdmin.change_view | {} |
| ^$                   | questions_question_changelist | django.contrib.admin.options.ModelAdmin.changelist_view | {} |
| ^(.+)/delete/$       | questions_question_delete | django.contrib.admin.options.ModelAdmin.delete_view | {} |
| ^(.+)/history/$      | questions_question_history | django.contrib.admin.options.ModelAdmin.history_view | {} |
| ^setlang/$           | set_language         | django.views.i18n.set_language | {} |
| ^add/$               | snippets_snippet_add | django.contrib.admin.options.ModelAdmin.add_view | {} |
| ^(.+)/change/$       | snippets_snippet_change | django.contrib.admin.options.ModelAdmin.change_view | {} |
| ^$                   | snippets_snippet_changelist | django.contrib.admin.options.ModelAdmin.changelist_view | {} |
| ^(.+)/delete/$       | snippets_snippet_delete | django.contrib.admin.options.ModelAdmin.delete_view | {} |
| ^(.+)/history/$      | snippets_snippet_history | django.contrib.admin.options.ModelAdmin.history_view | {} |
| solution/(?P<pk>\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/(?P<slug>[-_\w]+)/$ | solution             | apps.solutions.views.SolutionDetailView | {} |
| suit/(?P<slug>[-\w]+)/$ | suit                 | apps.testing.views.SuitDetailView | {} |
| tag/(?P<name>[-_\w]+)/$ | tag                  | apps.tags.views.TagDetailView | {} |
| theme/(?P<slug>[-_\w]+)/$ | theme                | apps.forum.views.SectionDetailView | {} |
| topic/(?P<slug>[-_\w]+)/$ | topic                | apps.forum.views.TopicDetailView | {} |
| update/$             | update               | apps.users.views.UserDetailView | {} |
| ^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$ | view_on_site         | django.contrib.contenttypes.views.shortcut | {} |
| writer/(?P<slug>[-_\w]+)/$ | writer               | apps.books.views.WriterDetailView | {} |
----------------------------------------------------------------------------------------------------

4
请注意,文档建议您不要使用print,而是使用self.stdout.write。https://docs.djangoproject.com/en/1.10/howto/custom-management-commands/ - Dustin Wyatt
我需要查看/按命名空间排序,并查看所有URL部分,因此在https://dev59.com/AnM_5IYBdhLWcg3wrFMt#42388839中扩展了此命令。 - Andrei
1
@Andrei,如果您已经产生了输出结果并分享给其他用户,那么他们就能够看到您的方法对我的好处。 - PADYMKO

16

activestate上有一个食谱。

import urls

def show_urls(urllist, depth=0):
    for entry in urllist:
        print("  " * depth, entry.regex.pattern)
        if hasattr(entry, 'url_patterns'):
            show_urls(entry.url_patterns, depth + 1)

show_urls(urls.url_patterns)

1
最后一行应该是 show_urls(urls.url_patterns) - Daniel Quinn
1
我收到了 ModuleNotFoundError: No module named 'urls' 的错误提示,不知道为什么? - Alexey
1
@Alexey 这可能与django 2有关。您能确认一下吗?这样我就可以更新答案了。 - pmav99
我将这段代码放在项目根目录下的test.py文件中,但是出现了这个错误。如果我在解释器中执行import urls命令,也会得到同样的错误。 - Alexey
1
这不是Django 1与2的问题:import urls是本地导入,所以你可能需要执行from app_name import urls - Aaron Klein

10

9

最佳且最实用的答案 - Manuel
这是我使用的方式,但是我遇到了一个限制:它(不总是?)无法展开包含的 URL 模块。 - DJ Ramones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接