Django: Comment puis-je voir une liste de modèles d'url?

130

Comment puis-je voir les urlpatterns actuels que "reverse" recherche?

J'appelle inverse dans une vue avec un argument qui, à mon avis, devrait fonctionner, mais qui ne le fait pas. De toute façon, je peux vérifier ce qu'il y a et pourquoi mon modèle ne l'est pas?

interstar
la source
Activez le mode DEBUG et regardez la liste des URL dans la sortie de débogage?
boatcoder

Réponses:

181

Si vous voulez une liste de toutes les urls de votre projet, vous devez d'abord installer django-extensions , ajoutez-le à vos paramètres comme ceci:

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

Et puis, exécutez cette commande dans votre terminal

./manage.py show_urls

Pour plus d'informations, vous pouvez consulter la documentation.

Robert
la source
3
En fait, je me suis trompé, cette fonctionnalité n'est pas fournie par django après tout.
robert
Tout ce que j'en tire, c'estTypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
Paul Tomblin
6
NB: vous devez ajouter django_extensionsà votre INSTALLED_APPSaprès l'installation
Owen
80

Essaye ça:

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

Ou si vous êtes toujours sur Django 1. *:

from django.core.urlresolvers import get_resolver
get_resolver(None).reverse_dict.keys()
SmileyChris
la source
9
cela renvoie les fonctions de vue, pas les URL
Ronen Ness
3
Pour qu'il renvoie les URL, faites ceci à la place: set (v [1] pour k, v dans get_resolver (None) .reverse_dict.iteritems ())
kloddant
4
Ou pour python3:set(v[1] for k,v in get_resolver(None).reverse_dict.items())
Privé
6
django.core.urlresolversa été supprimé dans Django 2.0 , remplacez la ligne d'importation parfrom django.urls import get_resolver
hoefling
2
cela ne fonctionne plus pour moi, ne rend qu'un petit sous-ensemble des URL de mon projet
J__
33

Solution Django> = 2.0

J'ai testé les autres réponses dans cet article et elles ne fonctionnaient pas avec Django 2.X, incomplètes ou trop complexes. Par conséquent, voici mon avis sur ceci:

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))

Ce code imprime toutes les URL, contrairement à certaines autres solutions, il imprimera le chemin complet et pas seulement le dernier nœud. par exemple:

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
Cesar Canassa
la source
1
Comment puis-je faire si je veux obtenir l'URL et le nom de la vue ... Parce que moi je veux obtenir le nom de la vue et le motif comme votre résultat ... S'il vous plaît comment?
Nathan Ingram
@NathanIngram La vue est stockée dans la propriété "callback" de l'objet URLPattern, vous pouvez donc changer la yield acc + [str(l.pattern)]ligne en yield acc + [str(l.pattern)], l.callback. Gardez à l'esprit qu'il renverra la fonction de vue elle-même et non un nom
Cesar Canassa
J'obtiens une erreur: --- >>>> TypeError: élément de séquence 0: instance de str attendue, liste trouvée
Nathan Ingram
@NathanIngram Le "print (''. Join (p))" ne fonctionnera pas car c'est maintenant une liste de tuples au lieu d'une liste de chaînes, essayez "print (''. Join (p [0]))".
Cesar Canassa le
22

Django 1.11, Python 2.7.6

cd to_your_django_project

shell python manage.py

Puis collez le code suivant.

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)

Exemple de sortie:

^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/^(.+)/$
...
petit mammifère
la source
C'est la réponse qui a fonctionné pour moi, même si j'ai dû ajouter Noneà la ligne urls = urlresolvers.get_resolver(None), et j'ai parfois obtenu «Aucun» au début de certaines URL.
Chris
17

Il y a une recette sur 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)
pmav99
la source
1
Cette dernière ligne devrait être show_urls(urls.url_patterns).
Daniel Quinn
1
Je reçois ModuleNotFoundError: No module named 'urls', je ne sais pas pourquoi?
Alexey
1
@Alexey C'est quelque chose qui a probablement à voir avec django 2. Pouvez-vous le confirmer s'il vous plaît afin que je puisse mettre à jour la réponse?
pmav99
J'ai placé ce code dans le fichier test.pyà la racine de mon projet et j'ai cette erreur, même si je le fais import urlsdans l'interpréteur, j'obtiens également cette erreur.
Alexey
Ce n'est pas un problème Django 1 vs 2: il import urlss'agit d'une importation locale, vous devez donc probablement le faire from app_name import urls.
Aaron Klein
16

J'utilise la commande suivante:

(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

Exemple de sortie:

----------------------------------------------------------------------------------------------------
| ^(.+)/$              |                      | 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 | {} |
----------------------------------------------------------------------------------------------------
PADYMKO
la source
4
Notez que la documentation vous recommande de ne pas utiliser print. Utilisez plutôt self.stdout.write. docs.djangoproject.com/en/1.10/howto/custom-management-commands
Dustin Wyatt
J'avais besoin de voir / trier par les espaces de noms et de voir également toutes les parties d'url, donc étendu cette commande dans stackoverflow.com/a/42388839/179581
Andrei
1
@Andrei, si vous avez fait une sortie à partir de votre réponse, cela donnerait aux autres utilisateurs la possibilité de voir un avantage de votre méthode sur moi
PADYMKO
7
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

Dans python manage.py shell

import urls
get_resolved_urls(urls.urlpatterns)
Sandeep
la source
4

Dans Django 3.0, c'est aussi simple que:

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

Impressions: [<URLPattern '' [name='home']>, <URLPattern '/testing' [name='another_url']>]

Cameron Sima
la source
3

J'ai étendu la commande de Seti pour afficher l'espace de noms, toutes les parties d'url, ajuster automatiquement les largeurs de colonne, triées par (espace de noms, nom): 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()

Remarque: l' ordre des colonnes est conservé dans Python 3.6 et il faudrait l'utiliser OrderedDictdans les anciennes versions.

Mise à jour: Une nouvelle version avec OrderedDict vit désormais dans le package django-🍌s: https://github.com/5monkeys/django-bananas/blob/master/bananas/management/commands/show_urls.py

Andrei
la source
1
de django.conf.urls import RegexURLPattern, RegexURLResolver n'est pas plus valide dans django> 2.0 Mais j'ai adapté l'essentiel et fonctionne très bien maintenant,
merci
J'ai récemment fait face à ce problème et mis à jour l'essentiel. Il faudrait utiliser une révision antérieure pour fonctionner sur Django <2.0.
Andrei
2

Solution minimaliste pour django 2.0

Par exemple, si vous recherchez une URL qui se trouve sur la première application de installed_apps, vous pouvez y accéder comme ça:

from django.urls import get_resolver
from pprint import pprint

pprint(
    get_resolver().url_patterns[0].url_patterns
)

la source
Fonctionne aussi pour Django 1. * si vous importez get_resolverdepuis django.core.urlresolvers. Merci Marcio!
Fernando Costa Bertoldi le
2

Django 1.8, Python 2.7+ Exécutez simplement ces commandes dans votre Shell. Python manage.py shell et exécutez le code suivant.

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)
Aditya Saini
la source
1
Pourriez-vous s'il vous plaît fournir plus de détails sur votre réponse?
toshiro92
1
J'ai édité ma réponse, vous devez l'exécuter dans votre shell.
Aditya Saini le
0

Vous pouvez créer une importation dynamique pour rassembler tous les modèles d'URL de chaque application de votre projet avec une méthode simple comme celle-ci:

def get_url_patterns():
    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()

J'ai récemment utilisé quelque chose comme celui-ci pour créer une balise de modèle pour afficher les liens de navigation actifs.

ViaTech
la source
0
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

Voici your_main_apple nom de l'application où votre fichier settings.py est placé

nazmul_94_hasan
la source