You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django模型中获取所有URL名称列表?

解决方案

1. 修复URL名称提取函数(支持嵌套URL+避免循环导入)

先把提取URL名称的函数放到独立工具模块(比如utils/url_utils.py),同时修复原来的缺陷——原来的代码没法获取include()引入的子URL名称,还要处理递归遍历:

import importlib
from django.apps import apps
from django.urls.resolvers import URLResolver, URLPattern

def get_url_names():
    url_names = []
    
    # 递归遍历所有URL配置,包括嵌套的
    def traverse_urlpatterns(urlpatterns):
        for pattern in urlpatterns:
            if isinstance(pattern, URLResolver):
                traverse_urlpatterns(pattern.url_patterns)
            elif isinstance(pattern, URLPattern) and pattern.name:
                # 只收集有名称的URL,格式为(值, 显示文本)
                url_names.append((pattern.name, pattern.name))
    
    for app_name, app_config in apps.app_configs.items():
        mod_path = f"{app_name}.urls"
        try:
            urls_module = importlib.import_module(mod_path)
            if hasattr(urls_module, 'urlpatterns'):
                traverse_urlpatterns(urls_module.urlpatterns)
        except ImportError:
            # 跳过没有urls模块的应用
            pass
    
    # 去重,避免不同应用有同名URL
    return list(dict.fromkeys(url_names))

2. 动态设置choices,避开模型加载的坑

模型字段的choices是静态参数,在模型加载时就会被计算——这时候URL配置还没完全初始化,还容易触发循环导入。所以别直接在模型里绑定,改用以下两种方式:

方式一:仅在Admin后台使用动态选项

如果只需要在后台管理中显示下拉,直接修改Admin类:

from django.contrib import admin
from .models import RelativeLink
from .utils.url_utils import get_url_names

@admin.register(RelativeLink)
class RelativeLinkAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super().formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'page':
            # 动态加载最新的URL名称作为选项
            field.choices = get_url_names()
        return field

方式二:自定义表单(前端+后台通用)

如果前端表单也需要这个下拉,先定义ModelForm:

from django import forms
from .models import RelativeLink
from .utils.url_utils import get_url_names

class RelativeLinkForm(forms.ModelForm):
    class Meta:
        model = RelativeLink
        fields = '__all__'
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 表单初始化时才加载URL选项
        self.fields['page'].choices = get_url_names()

然后在Admin中指定使用这个表单:

@admin.register(RelativeLink)
class RelativeLinkAdmin(admin.ModelAdmin):
    form = RelativeLinkForm

3. 可选:缓存URL名称提升性能

如果频繁调用get_url_names(),可以在App启动时提前缓存结果,避免重复遍历:
在主应用的apps.py中:

from django.apps import AppConfig
from .utils.url_utils import get_url_names

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app_name'
    
    def ready(self):
        # 启动时缓存URL名称
        global cached_url_names
        cached_url_names = get_url_names()

然后修改url_utils.py中的函数,优先用缓存:

cached_url_names = None

def get_url_names():
    global cached_url_names
    if cached_url_names is not None:
        return cached_url_names
    
    # 原来的遍历逻辑...

原方案失效的原因

  1. 循环导入:模型文件导入提取函数,函数又导入应用的urls模块,而urls可能又导入模型,形成闭环。
  2. 时机不对:模型加载时,Django的URL配置还没完全初始化,此时调用函数会拿到空的urlpatterns。
  3. 函数缺陷:没处理include()的嵌套URL,导致大量URL名称被遗漏。

内容的提问来源于stack exchange,提问作者shsotoudegan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 08:31:02