How can I see the current urlpatterns that "reverse" is looking in?
I'm calling reverse in a view with an argument that I think should work, but doesn't. Any way I can check what's there and why my pattern isn't?
How can I see the current urlpatterns that "reverse" is looking in?
I'm calling reverse in a view with an argument that I think should work, but doesn't. Any way I can check what's there and why my pattern isn't?
If you want a list of all the urls in your project, first you need to install django-extensions
You can simply install using command.
pip install django-extensions For more information related to package goto django-extensions
After that, add django_extensions in INSTALLED_APPS in your settings.py file like this:
INSTALLED_APPS = ( ... 'django_extensions', ... ) urls.py example:
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) ] And then, run any of the command in your terminal
python manage.py show_urls or
./manage.py show_urls Sample output example based on config 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 For more information you can check the documentation.
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'django_extensions to your INSTALLED_APPS after installingTry this:
from django.urls import get_resolver get_resolver().reverse_dict.keys() Or if you're still on Django 1.*:
from django.core.urlresolvers import get_resolver get_resolver(None).reverse_dict.keys() set(v[1] for k,v in get_resolver(None).reverse_dict.items())django.core.urlresolvers was removed in Django 2.0, replace the import line with from django.urls import get_resolverI tested the other answers in this post and they were either not working with Django 2.X, incomplete or too complex. Therefore, here is my take on this:
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)) This code prints all URLs, unlike some other solutions it will print the full path and not only the last node. e.g.:
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 yield acc + [str(l.pattern)] line to yield acc + [str(l.pattern)], l.callback. Keep in mind that it will return the view function itself and not a nameyield acc + [str(l.pattern)] to yield [l.callback.view_class]Here is a quick and dirty hack to just get the information you need without needing to modify any of your settings.
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())' This is piggy backing off @robert's answer. While correct, I didn't want to have django-extensions as a dependency even if it was for just a second.
Django 1.11, Python 2.7.6
cd to_your_django_project
python manage.py shell
Then paste following code.
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) Sample output:
^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/^(.+)/$ ... None to the line urls = urlresolvers.get_resolver(None), and I did sometimes get 'None' at the start of some URLs.In Django 3.0, it's as easy as:
>>> from django.urls import get_resolver >>> print(get_resolver().url_patterns) [<URLPattern '' [name='home']>, <URLPattern '/testing' [name='another_url']>] To get the patterns for a particular app, you could use the following:
from django.urls import get_resolver, URLPattern def get_patterns(app: str) -> List[URLPattern]: for pattern in get_resolver().url_patterns: if getattr(pattern, "app_name", "") == app: return pattern.urlconf_name >>> get_patterns("admin") [<URLPattern '' [name='index']>, <URLPattern 'login/' [name='login']>, <URLPattern 'logout/' [name='logout']>, <URLPattern 'password_change/' [name='password_change']>, <URLPattern 'password_change/done/' [name='password_change_done']>, <URLPattern 'autocomplete/' [name='autocomplete']>, <URLPattern 'jsi18n/' [name='jsi18n']> [<URLResolver <URLPattern list> (None:None) 'api/v1/'>, <URLPattern '^$'>, <URLPattern '^media/(?P<path>.*)$'>]I am using the next command:
(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) Usage:
./manage.py showurls Sample output:
---------------------------------------------------------------------------------------------------- | ^(.+)/$ | | 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 | {} | ---------------------------------------------------------------------------------------------------- print. Instead use self.stdout.write. docs.djangoproject.com/en/1.10/howto/custom-management-commandsThere is a recipe on 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) show_urls(urls.url_patterns).ModuleNotFoundError: No module named 'urls', dont know why?test.py in the root of my project and has this error, also if i do import urls in interpreter then i also get this error.import urls is a local import, so you probably need to do from app_name import urls.There's a plugin I use: https://github.com/django-extensions/django-extensions, it has a show_urls command that could help.
Simply type in a url you know does not exist and the server will return an error message with a list of url patterns.
For example, if you're running a site at http://localhost:8000/something
Type in
http://localhost:8000/something/blahNonsense, and your server will return the url search list and display it in the browser
def get_resolved_urls(url_patterns): url_patterns_resolved = [] for entry in url_patterns: if hasattr(entry, 'url_patterns'): url_patterns_resolved += get_resolved_urls( entry.url_patterns) else: url_patterns_resolved.append(entry) return url_patterns_resolved In python manage.py shell
import urls get_resolved_urls(urls.urlpatterns) Minimalist solution for django 2.0
For instance, if you're looking for an url that's on the first app of installed_apps, you can access it like that:
from django.urls import get_resolver from pprint import pprint pprint( get_resolver().url_patterns[0].url_patterns ) get_resolver from django.core.urlresolvers. Thanks Marcio!I have extended Seti's command to show namespace, all url parts, auto-adjust column widths, sorted by (namespace,name): https://gist.github.com/andreif/263a3fa6e7c425297ffee09c25f66b20
import sys from django.core.management import BaseCommand from django.conf.urls import RegexURLPattern, RegexURLResolver from django.core import urlresolvers def collect_urls(urls=None, namespace=None, prefix=None): if urls is None: urls = urlresolvers.get_resolver() _collected = [] prefix = prefix or [] for x in urls.url_patterns: if isinstance(x, RegexURLResolver): _collected += collect_urls(x, namespace=x.namespace or namespace, prefix=prefix + [x.regex.pattern]) elif isinstance(x, RegexURLPattern): _collected.append({'namespace': namespace or '', 'name': x.name or '', 'pattern': prefix + [x.regex.pattern], 'lookup_str': x.lookup_str, 'default_args': dict(x.default_args)}) else: raise NotImplementedError(repr(x)) return _collected def show_urls(): all_urls = collect_urls() all_urls.sort(key=lambda x: (x['namespace'], x['name'])) max_lengths = {} for u in all_urls: for k in ['pattern', 'default_args']: u[k] = str(u[k]) for k, v in list(u.items())[:-1]: # Skip app_list due to length (contains all app names) if (u['namespace'], u['name'], k) == \ ('admin', 'app_list', 'pattern'): continue max_lengths[k] = max(len(v), max_lengths.get(k, 0)) for u in all_urls: sys.stdout.write(' | '.join( ('{:%d}' % max_lengths.get(k, len(v))).format(v) for k, v in u.items()) + '\n') class Command(BaseCommand): def handle(self, *args, **kwargs): show_urls() Note: column order is kept in Python 3.6 and one would need to use
OrderedDictin older versions.
Update: A new version with OrderedDict now lives in django-🍌s package: https://github.com/5monkeys/django-bananas/blob/master/bananas/management/commands/show_urls.py
Django 1.8, Python 2.7+ Just run these commands in your Shell. Python manage.py shell and execute the following code.
from django.conf.urls import RegexURLPattern, RegexURLResolver from django.core import urlresolvers urls = urlresolvers.get_resolver(None) 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) from django.urls.resolvers import RegexPattern,RoutePattern from your_main_app import urls def get_urls(): url_list = [] for url in urls.urlpatterns: url_list.append(url.pattern._regex) if isinstance(url.pattern, RegexPattern) else url_list.append(url.pattern._route) return url_list Here your_main_app is the app name where your settings.py file is placed
adopted from @CesarCanassa
from django.conf import settings from django.urls import URLPattern, URLResolver URLCONF = __import__(settings.ROOT_URLCONF, {}, {}, ['']) def list_urls(patterns, path=None): """ recursive """ if not path: path = [] result = [] for pattern in patterns: if isinstance(pattern, URLPattern): result.append(''.join(path) + str(pattern.pattern)) elif isinstance(pattern, URLResolver): result += list_urls(pattern.url_patterns, path + [str(pattern.pattern)]) return result Yet another adaption of @Cesar Canassa 's generator magic. This can be added to the yourapp/management/commands/dumpurls.py director of your app so that it'll be accessible as a subcommand in management.py.
note: I added a line to make sure it filters for only yourapp. Update or remove it accordingly if additional URLs are desired.
management.py SubcommandDeploy Path: yourapp/management/commands/dumpurls.py
from django.core.management.base import BaseCommand, CommandError from django.conf import settings from django.urls import URLPattern, URLResolver 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),l.name] elif isinstance(l, URLResolver): yield from list_urls(l.url_patterns, acc + [str(l.pattern)]) yield from list_urls(lis[1:], acc) class Command(BaseCommand): help = 'List all URLs from the urlconf' def handle(self, *args, **options): urlconf = __import__(settings.ROOT_URLCONF, {}, {}, ['']) records, glen, nlen = [], 0, 0 for p in list_urls(urlconf.urlpatterns): record = [''.join(p[:2]), p[2]] # Update me, or add an argument if record[0].startswith('yourapp'): clen = len(record[0]) if clen > glen: glen = clen clen = len(record[1]) if clen > nlen: nlen = clen records.append(record) self.stdout.write('{:-<{width}}'.format('',width=glen+nlen)) self.stdout.write('{:<{glen}}Name'.format('Path',glen=glen+4)) self.stdout.write('{:-<{width}}'.format('',width=glen+nlen)) for record in records: self.stdout.write('{path:<{glen}}{name}'.format(path=record[0], name=record[1], glen=glen+4)) self.stdout.write('{:-<{width}}'.format('',width=glen+nlen)) (env) django@dev:myproj~> ./manage.py dumpurls ------------------------------------------------------------------------------------------------------- Path Name ------------------------------------------------------------------------------------------------------- yourapp/^api-key/$ api-key-list yourapp/^api-key\.(?P<format>[a-z0-9]+)/?$ api-key-list yourapp/^attacks/$ attack-list yourapp/^attacks\.(?P<format>[a-z0-9]+)/?$ attack-list yourapp/^attack-histories/$ attackhistory-list yourapp/^attack-histories\.(?P<format>[a-z0-9]+)/?$ attackhistory-list yourapp/^files/$ file-list yourapp/^files\.(?P<format>[a-z0-9]+)/?$ file-list yourapp/^modules/$ module-list yourapp/^modules\.(?P<format>[a-z0-9]+)/?$ module-list You can create a dynamic import to gather all URL Patterns from each application in your project with a simple method like so:
def get_url_patterns(): import importlib from django.apps import apps list_of_all_url_patterns = list() for name, app in apps.app_configs.items(): # you have a directory structure where you should be able to build the correct path # my example shows that apps.[app_name].urls is where to look mod_to_import = f'apps.{name}.urls' try: urls = getattr(importlib.import_module(mod_to_import), "urlpatterns") list_of_all_url_patterns.extend(urls) except ImportError as ex: # is an app without urls pass return list_of_all_url_patterns list_of_all_url_patterns = get_url_patterns()
I recently used something like this to create a template tag to show active navigation links.
import subprocces res = subprocess.run( 'python manage.py show_urls', capture_output=True, shell=True, ) url_list = [ line.split('\t')[0] for line in res.stdout.decode().split('\n') ] subprocess.run() allows you to run command line executables from python. You can pass the show_urls argument to manage.py, capture the output, which has to use the shell option (by default - as far as I know) and save it to the res variable. url_list is then a list... it uses a "generator" structure to generate each list item. Assuming that res outputs coded URLs with a \t character at the end of each one, we take a list item and split it then take the remainder (the first element), ie [item for line in ...]. ... is needed to iterate over all URLs and read them.In case you are using DRF, you can print all the URL patterns for a particular router by printing the urlpatterns from router.get_urls() (within your Django app's urls.py file).
Open your apps urls.py and add the print statement to the bottom of the file, so the whole file might look like this:
import pprint from django.urls import include, path from rest_framework import routers from . import views router = routers.DefaultRouter() router.register(r"users", views.UserViewSet, basename="User") router.register(r"auth", views.AuthenticationView, basename="Auth") router.register(r"dummy", views.DummyViewSet, basename="Dummy") router.register("surveys", views.SurveyViewSet, basename="survey") urlpatterns = [ path("", include(router.urls)), ] pprint.pprint(router.get_urls()) The patterns are then printed like this:
[<URLPattern '^users/$' [name='User-list']>, <URLPattern '^users\.(?P<format>[a-z0-9]+)/?$' [name='User-list']>, <URLPattern '^users/admins/$' [name='User-admins']>, <URLPattern '^users/admins\.(?P<format>[a-z0-9]+)/?$' [name='User-admins']>, <URLPattern '^users/current/$' [name='User-current']>, <URLPattern '^users/current\.(?P<format>[a-z0-9]+)/?$' [name='User-current']>, <URLPattern '^users/(?P<pk>[^/.]+)/$' [name='User-detail']>, <URLPattern '^users/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='User-detail']>, <URLPattern '^auth/login/$' [name='Auth-login']>, ... ] In my case I want to list api endpoints without having to basically rewrite my urlpatterns. You can't import urlpatterns into the view since it causes a circular import. So here is a pretty good solution using the include function from django.urls. This allows you to list any set of urlpatterns in the project.
from django.views.generic import TemplateView from rest_framework.response import Response from rest_framework.routers import APIRootView from rest_framework.schemas import get_schema_view from django.urls import include import re # Create your views here. class ApiRoot(APIRootView): def get(self, request, *args, **kwargs): urls = include('api.urls')[0].urlpatterns response = {} for url in urls: match = re.search(r'[\w\/\-]+', str(url.pattern)) if not match: continue name = match.group() response[name] = request.build_absolute_uri(name) return Response(response)
Copy and paste this and fix up some stuff. Hacky solution that works great for me.
If you just want to browse them all, just go to, e.g.:
http://127.0.0.1:8000/admin/doc/views/