mirror of
https://github.com/django/django.git
synced 2025-04-05 05:56:42 +00:00
Fixed #28800 -- Added a listurls management command
This commit is contained in:
parent
b9aa3239ab
commit
4dfae3a3c2
1
AUTHORS
1
AUTHORS
@ -1036,6 +1036,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Tyson Clugg <tyson@clugg.net>
|
||||
Tyson Tate <tyson@fallingbullets.com>
|
||||
Unai Zalakain <unai@gisa-elkartea.org>
|
||||
Ülgen Sarıkavak <https://github.com/ulgens>
|
||||
Valentina Mukhamedzhanova <umirra@gmail.com>
|
||||
valtron
|
||||
Vasiliy Stavenko <stavenko@gmail.com>
|
||||
|
275
django/core/management/commands/listurls.py
Normal file
275
django/core/management/commands/listurls.py
Normal file
@ -0,0 +1,275 @@
|
||||
import json
|
||||
from importlib import import_module
|
||||
from io import StringIO
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.admindocs.views import (
|
||||
extract_views_from_urlpatterns,
|
||||
simplify_regex,
|
||||
)
|
||||
from django.core.management import color
|
||||
from django.core.management.base import BaseCommand, CommandError, CommandParser
|
||||
from django.utils import termcolors
|
||||
|
||||
FORMATS = (
|
||||
"aligned",
|
||||
"table",
|
||||
"verbose",
|
||||
"json",
|
||||
"pretty-json",
|
||||
)
|
||||
|
||||
|
||||
COLORLESS_FORMATS = (
|
||||
"json",
|
||||
"pretty-json",
|
||||
)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "List URL patterns in the project with optional filtering by prefixes."
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.style.HEADER = termcolors.make_style(opts=("bold",))
|
||||
self.style.ROUTE = termcolors.make_style(opts=("bold",))
|
||||
self.style.VIEW_NAME = termcolors.make_style(fg="yellow", opts=("bold",))
|
||||
self.style.NAME = termcolors.make_style(fg="red", opts=("bold",))
|
||||
|
||||
def add_arguments(self, parser: CommandParser):
|
||||
super().add_arguments(parser)
|
||||
|
||||
# Sorting
|
||||
parser.add_argument(
|
||||
"--unsorted",
|
||||
"-u",
|
||||
action="store_true",
|
||||
dest="unsorted",
|
||||
help="Filter URLs by the given prefix[es]",
|
||||
)
|
||||
|
||||
# Prefix
|
||||
parser.add_argument(
|
||||
"--prefix",
|
||||
"-p",
|
||||
dest="prefixes",
|
||||
help="Only list URLs with these prefixes.",
|
||||
nargs="*",
|
||||
)
|
||||
|
||||
# Format
|
||||
parser.add_argument(
|
||||
"--format",
|
||||
"-f",
|
||||
choices=FORMATS,
|
||||
default="aligned",
|
||||
dest="format",
|
||||
help="Formatting style of the output",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Make sure the prefixes are a list
|
||||
prefixes = options["prefixes"]
|
||||
if prefixes:
|
||||
prefixes = prefixes if isinstance(prefixes, list) else [prefixes]
|
||||
|
||||
url_patterns = get_url_patterns(prefixes=prefixes)
|
||||
|
||||
if not url_patterns:
|
||||
raise CommandError("There are no URL patterns that match given prefixes")
|
||||
|
||||
unsorted = options["unsorted"]
|
||||
no_color = options["no_color"]
|
||||
format = options["format"]
|
||||
|
||||
# Apply sorting
|
||||
if not unsorted:
|
||||
url_patterns.sort()
|
||||
|
||||
# Apply colors
|
||||
if (
|
||||
color.supports_color()
|
||||
and (not no_color)
|
||||
and (format not in COLORLESS_FORMATS)
|
||||
):
|
||||
url_patterns = self.apply_color(url_patterns=url_patterns)
|
||||
|
||||
# Apply formatting
|
||||
url_patterns = self.apply_format(
|
||||
url_patterns=url_patterns,
|
||||
format=format,
|
||||
)
|
||||
|
||||
return url_patterns
|
||||
|
||||
def apply_color(self, url_patterns):
|
||||
colored_url_patterns = []
|
||||
|
||||
for url_pattern in url_patterns:
|
||||
# Route
|
||||
route = url_pattern[0]
|
||||
route = self.style.ROUTE(route)
|
||||
|
||||
# View
|
||||
view = url_pattern[1]
|
||||
module_path, module_name = view.rsplit(".", 1)
|
||||
module_name = self.style.VIEW_NAME(module_name)
|
||||
view = f"{module_path}.{module_name}"
|
||||
|
||||
# Name
|
||||
name = url_pattern[2]
|
||||
if name:
|
||||
namespace, name = name.rsplit(":", 1) if ":" in name else ("", name)
|
||||
name = self.style.NAME(name)
|
||||
name = f"{namespace}:{name}" if namespace else name
|
||||
|
||||
# Append to the list
|
||||
colored_url_patterns.append((route, view, name))
|
||||
|
||||
return colored_url_patterns
|
||||
|
||||
def apply_format(self, url_patterns, format):
|
||||
format_method_name = f"format_{format.replace('-', '_')}"
|
||||
format_method = getattr(self, format_method_name)
|
||||
|
||||
return format_method(url_patterns)
|
||||
|
||||
def format_table(self, url_patterns):
|
||||
formatted_str = StringIO()
|
||||
|
||||
widths = []
|
||||
margin = 2
|
||||
for columns in zip(*url_patterns, strict=False):
|
||||
widths.append(len(max(columns, key=len)) + margin)
|
||||
|
||||
# Headers
|
||||
headers = (
|
||||
self.style.HEADER("Route"),
|
||||
self.style.HEADER("View"),
|
||||
self.style.HEADER("Name"),
|
||||
)
|
||||
|
||||
header_parts = []
|
||||
for width, header in zip(widths, headers, strict=False):
|
||||
header_parts.append(header.ljust(width))
|
||||
|
||||
formatted_str.write(" | ".join(header_parts))
|
||||
formatted_str.write("\n")
|
||||
|
||||
# Header - content seperator
|
||||
formatted_str.write("-+-".join("-" * width for width in widths))
|
||||
formatted_str.write("\n")
|
||||
|
||||
# Rows (content)
|
||||
for row in url_patterns:
|
||||
row_parts = []
|
||||
|
||||
for width, cdata in zip(widths, row, strict=False):
|
||||
row_parts.append(cdata.ljust(width))
|
||||
|
||||
formatted_str.write(" | ".join(row_parts))
|
||||
formatted_str.write("\n")
|
||||
|
||||
return formatted_str.getvalue()
|
||||
|
||||
def format_aligned(self, url_patterns):
|
||||
formatted_str = StringIO()
|
||||
|
||||
widths = []
|
||||
for columns in zip(*url_patterns, strict=False):
|
||||
margin = 2
|
||||
widths.append(len(max(columns, key=len)) + margin)
|
||||
|
||||
for row in url_patterns:
|
||||
for width, cdata in zip(widths, row, strict=False):
|
||||
formatted_str.write(cdata.ljust(width))
|
||||
|
||||
formatted_str.write("\n")
|
||||
|
||||
return formatted_str.getvalue()
|
||||
|
||||
def format_verbose(self, url_patterns):
|
||||
formatted_str = StringIO()
|
||||
|
||||
for route, view, name in url_patterns:
|
||||
route_str = f"{self.style.HEADER('Route:')} {route}"
|
||||
view_str = f"{self.style.HEADER('View:')} {view}"
|
||||
name_str = f"{self.style.HEADER('Name:')} {name}" if name else ""
|
||||
|
||||
seperator = "-" * 20 + "\n"
|
||||
parts = (
|
||||
route_str,
|
||||
view_str,
|
||||
name_str,
|
||||
seperator,
|
||||
)
|
||||
|
||||
formatted_str.write("\n".join(part for part in parts if part))
|
||||
|
||||
return formatted_str.getvalue()
|
||||
|
||||
def format_json(self, url_patterns, pretty=False):
|
||||
indent = 4 if pretty else None
|
||||
|
||||
# Having keys in the resulting JSON makes it more useful
|
||||
url_pattern_dicts = []
|
||||
for route, view, name in url_patterns:
|
||||
url_pattern_dict = {
|
||||
"route": route,
|
||||
"view": view,
|
||||
"name": name,
|
||||
}
|
||||
url_pattern_dicts.append(url_pattern_dict)
|
||||
|
||||
return json.dumps(url_pattern_dicts, indent=indent)
|
||||
|
||||
def format_pretty_json(self, url_patterns):
|
||||
return self.format_json(url_patterns, pretty=True)
|
||||
|
||||
|
||||
def get_url_patterns(prefixes=None):
|
||||
"""
|
||||
Returns a list of URL patterns in the project with given prefixes.
|
||||
|
||||
Each object in the returned list is a tuple[str] with 3 elements:
|
||||
(route, view, name)
|
||||
"""
|
||||
|
||||
url_patterns = []
|
||||
urlconf = import_module(settings.ROOT_URLCONF)
|
||||
|
||||
for view_func, regex, namespace_list, name in extract_views_from_urlpatterns(
|
||||
urlconf.urlpatterns
|
||||
):
|
||||
# Route
|
||||
route = simplify_regex(regex)
|
||||
|
||||
# View
|
||||
view = "{}.{}".format(
|
||||
view_func.__module__,
|
||||
getattr(view_func, "__name__", view_func.__class__.__name__),
|
||||
)
|
||||
|
||||
# Name
|
||||
namespace = ""
|
||||
|
||||
if namespace_list:
|
||||
for part in namespace_list:
|
||||
namespace += part + ":"
|
||||
|
||||
name = namespace + name if name else None
|
||||
name = name or ""
|
||||
|
||||
# Append to the list
|
||||
url_patterns.append((route, view, name))
|
||||
|
||||
# Filter out when prefixes are given but the pattern's route doesn't match
|
||||
if prefixes:
|
||||
url_patterns = [
|
||||
url_pattern
|
||||
for url_pattern in url_patterns
|
||||
if any(url_pattern[0].startswith(prefix) for prefix in prefixes)
|
||||
]
|
||||
|
||||
return url_patterns
|
@ -498,6 +498,18 @@ Only support for PostgreSQL is implemented.
|
||||
|
||||
If this option is provided, models are also created for database views.
|
||||
|
||||
``listurls``
|
||||
------------
|
||||
|
||||
.. django-admin:: listurls [url_prefix ...]
|
||||
|
||||
Displays a list of the URLs and their associated short names and views in the
|
||||
project. Optionally restrict to one or more prefixes.
|
||||
|
||||
.. django-admin-option:: --table
|
||||
|
||||
Output the list of URLs as a table, one URL per line.
|
||||
|
||||
``loaddata``
|
||||
------------
|
||||
|
||||
|
@ -255,6 +255,9 @@ Management Commands
|
||||
``Command.autodetector`` attribute for subclasses to override in order to use
|
||||
a custom autodetector class.
|
||||
|
||||
* Introduce a :djadmin:`listurls` command that lists the URLs in the application,
|
||||
including the view function and name, if present.
|
||||
|
||||
Migrations
|
||||
~~~~~~~~~~
|
||||
|
||||
|
0
tests/admin_scripts/app_with_urls/__init__.py
Normal file
0
tests/admin_scripts/app_with_urls/__init__.py
Normal file
12
tests/admin_scripts/app_with_urls/root_urls.py
Normal file
12
tests/admin_scripts/app_with_urls/root_urls.py
Normal file
@ -0,0 +1,12 @@
|
||||
from django.urls import include, path
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
route="nons/",
|
||||
view=include("admin_scripts.app_with_urls.urls_nons"),
|
||||
),
|
||||
path(
|
||||
route="namespaced/",
|
||||
view=include("admin_scripts.app_with_urls.urls_namespaced", namespace="ns"),
|
||||
),
|
||||
]
|
17
tests/admin_scripts/app_with_urls/urls_namespaced.py
Normal file
17
tests/admin_scripts/app_with_urls/urls_namespaced.py
Normal file
@ -0,0 +1,17 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "app_with_urls"
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
route="unnamed",
|
||||
view=views.view_func_namespaced_unnamed,
|
||||
),
|
||||
path(
|
||||
route="named",
|
||||
view=views.view_func_namespaced_named,
|
||||
name="named",
|
||||
),
|
||||
]
|
17
tests/admin_scripts/app_with_urls/urls_nons.py
Normal file
17
tests/admin_scripts/app_with_urls/urls_nons.py
Normal file
@ -0,0 +1,17 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "app_with_urls"
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
route="unnamed",
|
||||
view=views.view_func_nons_unnamed,
|
||||
),
|
||||
path(
|
||||
route="named",
|
||||
view=views.view_func_nons_named,
|
||||
name="named",
|
||||
),
|
||||
]
|
14
tests/admin_scripts/app_with_urls/views.py
Normal file
14
tests/admin_scripts/app_with_urls/views.py
Normal file
@ -0,0 +1,14 @@
|
||||
def view_func_namespaced_unnamed(request):
|
||||
pass
|
||||
|
||||
|
||||
def view_func_namespaced_named(request):
|
||||
pass
|
||||
|
||||
|
||||
def view_func_nons_unnamed(request):
|
||||
pass
|
||||
|
||||
|
||||
def view_func_nons_named(request):
|
||||
pass
|
@ -4,6 +4,7 @@ advertised - especially with regards to the handling of the
|
||||
DJANGO_SETTINGS_MODULE and default settings.py files.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
@ -3148,6 +3149,286 @@ class Dumpdata(AdminScriptTestCase):
|
||||
self.assertNoOutput(out)
|
||||
|
||||
|
||||
class Listurls(AdminScriptTestCase):
|
||||
"""
|
||||
Tests for the listurls command.
|
||||
"""
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_default(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
# Check route, view and (if defined) name for each URL
|
||||
self.assertOutput(out, "/namespaced/named")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_named",
|
||||
)
|
||||
self.assertOutput(out, "ns:named")
|
||||
|
||||
self.assertOutput(out, "/namespaced/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_unnamed",
|
||||
)
|
||||
|
||||
self.assertOutput(out, "/nons/named")
|
||||
self.assertOutput(out, "admin_scripts.app_with_urls.views.view_func_nons_named")
|
||||
self.assertOutput(out, "app_with_urls:named")
|
||||
|
||||
self.assertOutput(out, "/nons/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_nons_unnamed",
|
||||
)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_aligned(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls", "-f", "aligned"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
# Check route, view and (if defined) name for each URL
|
||||
self.assertOutput(out, "/namespaced/named")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_named",
|
||||
)
|
||||
self.assertOutput(out, "ns:named")
|
||||
|
||||
self.assertOutput(out, "/namespaced/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_unnamed",
|
||||
)
|
||||
|
||||
self.assertOutput(out, "/nons/named")
|
||||
self.assertOutput(out, "admin_scripts.app_with_urls.views.view_func_nons_named")
|
||||
self.assertOutput(out, "app_with_urls:named")
|
||||
|
||||
self.assertOutput(out, "/nons/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_nons_unnamed",
|
||||
)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_table(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls", "-f", "table"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
# Check table headers
|
||||
self.assertOutput(out, "Route")
|
||||
self.assertOutput(out, "View")
|
||||
self.assertOutput(out, "Name")
|
||||
self.assertOutput(out, "---+---")
|
||||
|
||||
# Check route, view and (if defined) name for each URL
|
||||
self.assertOutput(out, "/namespaced/named")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_named",
|
||||
)
|
||||
self.assertOutput(out, "ns:named")
|
||||
|
||||
self.assertOutput(out, "/namespaced/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_unnamed",
|
||||
)
|
||||
|
||||
self.assertOutput(out, "/nons/named")
|
||||
self.assertOutput(out, "admin_scripts.app_with_urls.views.view_func_nons_named")
|
||||
self.assertOutput(out, "app_with_urls:named")
|
||||
|
||||
self.assertOutput(out, "/nons/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_nons_unnamed",
|
||||
)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_verbose(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls", "-f", "verbose"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
self.assertOutput(out, "Route:")
|
||||
self.assertOutput(out, "View:")
|
||||
self.assertOutput(out, "Name:")
|
||||
self.assertOutput(out, "-" * 20)
|
||||
|
||||
self.assertOutput(out, "/namespaced/named")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_named",
|
||||
)
|
||||
self.assertOutput(out, "ns:named")
|
||||
|
||||
self.assertOutput(out, "/namespaced/unnamed")
|
||||
self.assertOutput(
|
||||
out, "admin_scripts.app_with_urls.views.view_func_namespaced_unnamed"
|
||||
)
|
||||
|
||||
self.assertOutput(out, "/nons/named")
|
||||
self.assertOutput(out, "app_with_urls:named")
|
||||
self.assertOutput(out, "admin_scripts.app_with_urls.views.view_func_nons_named")
|
||||
|
||||
self.assertOutput(out, "/nons/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_nons_unnamed",
|
||||
)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_json(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls", "-f", "json"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
try:
|
||||
json.loads(out)
|
||||
except json.JSONDecodeError:
|
||||
self.fail("Output is not valid JSON")
|
||||
|
||||
self.assertOutput(out, '"route": "/namespaced/named"')
|
||||
self.assertOutput(
|
||||
out,
|
||||
'"view": "admin_scripts.app_with_urls.views.view_func_namespaced_named"',
|
||||
)
|
||||
self.assertOutput(out, '"name": "ns:named"')
|
||||
|
||||
self.assertOutput(out, '"route": "/namespaced/unnamed"')
|
||||
self.assertOutput(
|
||||
out,
|
||||
'"view": "admin_scripts.app_with_urls.views.view_func_namespaced_unnamed"',
|
||||
)
|
||||
|
||||
self.assertOutput(out, '"route": "/nons/named"')
|
||||
self.assertOutput(out, "admin_scripts.app_with_urls.views.view_func_nons_named")
|
||||
self.assertOutput(out, "app_with_urls:named")
|
||||
|
||||
self.assertOutput(out, "/nons/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_nons_unnamed",
|
||||
)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_pretty_json(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls", "-f", "pretty-json"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
self.assertOutput(out, "/namespaced/named")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_named",
|
||||
)
|
||||
self.assertOutput(out, "ns:named")
|
||||
|
||||
self.assertOutput(out, "/namespaced/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_namespaced_unnamed",
|
||||
)
|
||||
|
||||
self.assertOutput(out, "/nons/named")
|
||||
self.assertOutput(out, "app_with_urls:named")
|
||||
self.assertOutput(out, "admin_scripts.app_with_urls.views.view_func_nons_named")
|
||||
|
||||
self.assertOutput(out, "/nons/unnamed")
|
||||
self.assertOutput(
|
||||
out,
|
||||
"admin_scripts.app_with_urls.views.view_func_nons_unnamed",
|
||||
)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_unsorted(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
# JSON format is the easiest to parse and test
|
||||
args = ["listurls", "-f", "json", "--unsorted"]
|
||||
out, err = self.run_manage(args)
|
||||
url_patterns = json.loads(out)
|
||||
|
||||
self.assertNotEqual(
|
||||
url_patterns,
|
||||
sorted(url_patterns, key=lambda u: u["route"]),
|
||||
)
|
||||
|
||||
def test_no_urls(self):
|
||||
self.write_settings("settings.py")
|
||||
|
||||
args = ["listurls"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertOutput(err, "There are no URL patterns that match given prefixes")
|
||||
self.assertNoOutput(out)
|
||||
|
||||
@override_settings(ROOT_URLCONF="admin_scripts.app_with_urls.root_urls")
|
||||
def test_prefixes(self):
|
||||
self.write_settings(
|
||||
"settings.py",
|
||||
apps=["admin_scripts.app_with_urls"],
|
||||
)
|
||||
|
||||
args = ["listurls", "-p", "/namespaced"]
|
||||
out, err = self.run_manage(args)
|
||||
|
||||
self.assertNoOutput(err)
|
||||
|
||||
self.assertOutput(out, "/namespaced/named")
|
||||
self.assertOutput(out, "ns:named")
|
||||
self.assertOutput(out, "/namespaced/unnamed")
|
||||
|
||||
self.assertNotInOutput(out, "/nons/named")
|
||||
self.assertNotInOutput(out, "app_with_urls:named")
|
||||
self.assertNotInOutput(out, "/nons/unnamed")
|
||||
|
||||
|
||||
class MainModule(AdminScriptTestCase):
|
||||
"""python -m django works like django-admin."""
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user