如何获取 Django 应用程序中所有视图的列表?

问题描述 投票:0回答:4

有什么方法可以获取 Django 应用程序中所有视图的列表?我用谷歌搜索了答案。所有答案都显示了一种获取网址列表的方法。

django django-views
4个回答
16
投票

获取 Django 项目的所有视图列表:

为了获取 Django 项目中存在的所有视图,我们创建了一个函数

get_all_view_names()
,它将
urlpatterns
作为输入并返回项目中使用的完整视图列表作为输出。

首先,我们使用

root_urlconf
导入
settings.ROOT_URLCONF
模块。然后
root_urlconf.urls.urlpatterns
会给我们项目的 urlpatterns 列表。

上面的 urlpatterns 列表包含

RegexURLPattern
RegexURLResolver
对象。在
.urlpatterns
上访问
RegexURLResolver
将进一步为我们提供
RegexURLPattern
RegexURLResolver
对象的列表。

一个

RegexURLPattern
对象会给我们感兴趣的视图名称。它的
callback
属性包含可调用视图。当我们在我们的 url 中传递一个字符串,如
'foo_app.views.view_name'
表示模块的路径和视图函数名称,或可调用视图时,
callback
属性设置为此。进一步访问
.func_name
将为我们提供视图名称。

我们递归地调用函数

get_all_view_names()
并将从
RegexURLPattern
对象获得的视图名称添加到全局列表
VIEW_NAMES
.

from django.conf import settings
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern

root_urlconf = __import__(settings.ROOT_URLCONF) # import root_urlconf module
all_urlpatterns = root_urlconf.urls.urlpatterns # project's urlpatterns
VIEW_NAMES = [] # maintain a global list

def get_all_view_names(urlpatterns):
    global VIEW_NAMES
    for pattern in urlpatterns:
        if isinstance(pattern, RegexURLResolver):
            get_all_view_names(pattern.url_patterns) # call this function recursively
        elif isinstance(pattern, RegexURLPattern):
            view_name = pattern.callback.func_name # get the view name
            VIEW_NAMES.append(view_name) # add the view to the global list 
    return VIEW_NAMES

get_all_view_names(all_urlpatterns)

获取 Django 应用程序中所有视图的列表:

要获取 Django 应用程序中存在的所有视图的列表,我们将使用上面定义的

get_all_view_names()
函数。

我们会先导入应用程序的所有

urlpatterns
,并将这个列表传递给
get_all_view_names()
函数。

from my_app.urls import urlpatterns as my_app_urlpatterns # import urlpatterns of the app

my_app_views = get_all_view_names(my_app_urlpatterns) # call the function with app's urlpatterns as the argument

my_app_views
为我们提供了
my_app
Django 应用程序中存在的所有视图的列表。


10
投票

添加到 Rahul 的上述修复中,如果有人使用 Python3,您将需要使用

__name__
而不是
func_name

...
            view_name = pattern.callback.__name__
...

否则你会得到以下内容:

AttributeError: 'function' object has no attribute 'get_all_view_names'

(感谢 scipy-gitbot https://github.com/scipy/scipy/issues/2101#issuecomment-17027406

作为替代方案,如果您不愿意使用全局变量,这就是我最终使用的:

all_urlpatterns = __import__(settings.ROOT_URLCONF).urls.urlpatterns
detail_views_list = []

def get_all_view_names(urlpatterns):
    for pattern in urlpatterns:
        if isinstance(pattern, RegexURLResolver):
            get_all_view_names(pattern.url_patterns)
        elif isinstance(pattern, RegexURLPattern):
            detail_views_list.append(pattern.callback.__name__)
get_all_view_names(all_urlpatterns)
all_views_list = []

# remove redundant entries and specific ones we don't care about
for each in detail_views_list:
    if each not in "serve add_view change_view changelist_view history_view delete_view RedirectView":
        if each not in all_views_list:
            all_views_list.append(each)

然后您可以遍历

all_views_list
以获取过滤视图列表。

更新:2018 年 3 月 1 日

在 Django 2.0 中,

django.core.urlresolvers
被移动到
django.urls
RegexURLPattern
RegexURLResolver
更名为
URLPattern
URLResolver
。所以你应该使用

from django.urls import URLResolver, URLPattern

代替

from django.core.urlresolvers import RegexURLResolver, RegexURLPattern

如果您使用的是 Django 2.


2
投票

不使用全局变量获取所有 Django 和 DRF 视图

    def get_all_views(urlpatterns, views=None):
        views = views or {}
        for pattern in urlpatterns:
            if hasattr(pattern, 'url_patterns'):
                get_all_views(pattern.url_patterns, views=views)
            else:
                if hasattr(pattern.callback, 'cls'):
                    view = pattern.callback.cls
                elif hasattr(pattern.callback, 'view_class'):
                    view = pattern.callback.view_class
                else:
                    view = pattern.callback
                views[pattern.name] = view

        return views

0
投票

我需要计算项目的本地视图数。 这是执行此操作的代码.

这与当前答案不同,因为:

  • 它按视图对象而不是视图名称(可能与其他视图名称冲突)对视图进行分组
  • ModelAdmin
    类下的视图不包括在内
  • get_all_local_views
    函数仅返回当前目录(或
    settings.ROOT_DIR
    下)不在
    venv
    目录下的视图
from importlib import import_module
import inspect
from pathlib import Path
import importlib.util

from django.conf import settings
from django.contrib.admin.options import ModelAdmin
from django.urls import URLResolver, URLPattern


def is_modeladmin_view(view):
    """Return True if the view is an admin view."""
    view = inspect.unwrap(view)  # In case this is a decorated view
    self = getattr(view, "__self__", None)
    return self is not None and isinstance(self, ModelAdmin)


def get_all_views(urlpatterns):
    """Given a URLconf, return a set of all view objects."""
    views = set()
    for pattern in urlpatterns:
        if hasattr(pattern, "url_patterns"):
            views |= get_all_views(pattern.url_patterns)
        else:
            if hasattr(pattern.callback, "cls"):
                view = pattern.callback.cls
            elif hasattr(pattern.callback, "view_class"):
                view = pattern.callback.view_class
            else:
                view = pattern.callback
            if not is_modeladmin_view(view):
                views.add(view)
    return views


def get_module_path(module_name):
    """Return the path for a given module name."""
    spec = importlib.util.find_spec(module_name)
    if spec is None:
        raise ImportError(f"Module '{module_name}' not found")
    return Path(spec.origin).resolve()


def is_subpath(path, directory):
    """Return True if path is below directory and isn't within a "venv"."""
    try:
        path.relative_to(directory)
    except ValueError:
        return False
    else:
        # Return True if view isn't under a directory ending in "venv"
        return not any(p.endswith("venv") for p in path.parts)


def get_all_local_views():
    """Return a set of all local views in this project."""
    root_urlconf = import_module(settings.ROOT_URLCONF)
    all_urlpatterns = root_urlconf.urlpatterns
    try:
        root_directory = settings.ROOT_DIR
    except AttributeError:
        root_directory = Path.cwd()  # Assume we're in the root directory
    return {
        view
        for view in get_all_views(all_urlpatterns)
        if is_subpath(get_module_path(view.__module__), root_directory)
    }


all_views = get_all_local_views()
print("Number of local views:", len(all_views))
© www.soinside.com 2019 - 2024. All rights reserved.