有什么方法可以获取 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 应用程序中存在的所有视图的列表,我们将使用上面定义的
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 应用程序中存在的所有视图的列表。
添加到 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
以获取过滤视图列表。
在 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.
不使用全局变量获取所有 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
我需要计算项目的本地视图数。 这是执行此操作的代码.
这与当前答案不同,因为:
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))