在 Django 1.4 中,“admin”不是一个已注册的命名空间。

19

我正在尝试将一个相当大的Django项目升级到最新发布的Django 1.4版本,并且在运行python manage.py test时遇到了一些问题。

许多在Django 1.3中通过的内部测试现在失败了,出现了我无法解决的非常奇怪的消息。其中出现最多的是:

NoReverseMatch: u'admin' is not a registered namespace

这是针对django.contrib.auth的密码更改测试而引发的问题,特别是其中之一:test_password_change_fails_with_mismatched_passwords (django.contrib.auth.tests.views.ChangePasswordTest)。奇怪的是,命名空间已经正确注册并且应用程序运行正常。我按照“新”的方式导入了admin:

url(r'^admin/', include(admin.site.urls)),
当我特别搜索此错误时,我只能找到人们使用旧方案导入管理URL的情况,没有任何与这个问题相关的内容。
我尝试逐个从INSTALLED_APPS中删除应用程序,但auth测试仍然无法通过。此外,当我从python manage.py shell加载Python解释器并执行reverse('admin:index')时,URL解析为/admin/而没有任何错误。我已经详细阅读了代码,但无法看出哪里会出错。
如我之前提到的,这不是唯一发生的错误。我还从test_site_profile_not_available (django.contrib.auth.tests.models.ProfileTestCase)测试中获得AttributeError: AUTH_PROFILE_MODULE,尽管AUTH_PROFILE_MODULE在我的settings.py文件中定义。 Django自己的测试怎么可能失败呢?

1
你的代码有问题。在正常情况下,Django测试不会失败。你只需要仔细检查一切。我曾经遇到过类似的错误,结果发现是我的urlpatterns中有一个括号不平衡。 - Chris Pratt
你最终发现了发生了什么吗?说实话,我也遇到了类似的问题,不确定发生了什么。最终我只好放弃将管理模板文件移动到自己的应用程序目录中。 - stormlifter
1
我在一些Django 1.5测试中遇到了同样的错误,比如test_middleware_disabled。我尝试按照被接受的答案建议的方式反转TEMPLATE_LOADERS的顺序,并从我的应用程序模板目录中删除了管理模板(正如Amir所建议的),但我仍然会收到错误提示。 - Anthony Roberts
6个回答

16

简短回答: 问题是您在应用程序的模板目录中复制了Django管理模板文件的副本,这些文件是从早期版本的Django复制的,然后您升级了Django但没有更新(重新复制)这些本地模板。

详细回答: 这个问题的主要原因是使用旧版的Django管理模板文件(这些文件安装在django本身安装的位置,通常是Python的site-packagesdist-packages目录)。 Django 1.5中有一个关于url模板标记的不兼容变化,其中第一个参数必须是字符串,来自Django 1.5发布说明:

值得注意的一个被弃用的功能是转向“新样式”url标记。在Django 1.3之前,像{% url myview %}这样的语法会被解释不正确(Django认为“myview”是视图的字面名称,而不是名为myview的模板变量)。 Django 1.3及以上版本引入了{% load url from future %}语法,以引入更正的行为,其中myview被视为变量。

所以,问题在于您在应用程序的一个模板文件夹中拥有管理员的模板文件的副本,这些文件是从早期版本的Django中复制的。这通常是为了覆盖默认管理员模板而完成的。由于标记不兼容的更改,请注意,这些过时的模板文件无法在新的Django环境中加载,并导致奇怪的错误:NoReverseMatch:u'admin'未注册名称空间

更改TEMPLATE_LOADERS条目的顺序将忽略本地管理员模板对默认模板文件的修改(因为默认的Django模板是通过filesystem.Loader完整路径加载的)。如果需要修改(通常情况下),则必须从新的Django安装模板中更新本地管理模板文件,并重新应用您的修改。

注意1: 当本地管理员模板比Django安装的默认模板更新时,会出现类似的情况,这似乎是你的情况。同样,更好的解决方法是更新所有管理员模板的副本。

注意2: 另一种可能导致此类错误的情况是使用virtualenv。例如,如果你正在使用virtualenv运行项目,但Django管理员模板的TEMPLATE_DIRS条目指向全局Python安装,则可能会出现此错误。


1
厉害的回答!我希望我能多次点赞,因为你真的值得。 - Craig Labenz

9
原来,这是由于我的设置文件中TEMPLATE_LOADERS键的顺序造成的。
我有以下内容:
TEMPLATE_LOADERS = (
    'django.template.loaders.app_directories.Loader',
    'django.template.loaders.filesystem.Loader',
)

当反转管理员URL时,出现了某种错误。将两者交换解决了这个问题。我很想知道是怎么发生的,因为在空的Django 1.4项目中无法复制。

可复制的问题是settings.AUTH_PROFILE_MODULEAttributeError。结果发现这是Django 1.4中的一个错误,在发布日此处记录。


我还没有找到解决方法,但如果有的话,我很想知道。这个问题的优先级很低,让我感到沮丧,因为它阻止了使用TDD或持续集成来测试代码。我尝试创建一个自定义的测试运行器,可以跳过特定的测试,但无法使其正常工作。我所知道的唯一解决方案(并不理想)是只测试您自己的应用程序。如果您使用django-nose,则这是默认行为。 - Rob Golding

5
尝试在urls.py文件中的include方法内添加namespace="admin"。
例如:url(r'^admin/', include("someUrlpattern", namespace="admin"))

2

app_directories模板加载器从INSTALLED_APPS模板目录加载模板,而filesystem加载器从TEMPLATE_DIRS设置中配置的templates目录加载模板。

将它们两个进行切换会产生很大的差异,因为如果您在应用程序中有自定义模板,则如果app_directories位于顶部,则不会加载该模板。如果filesystem加载器位于顶部,则django将首先在您的模板目录中查找模板,然后再从installed_apps中加载默认模板。

这就是为什么在空白的Django项目中无法复现此问题的原因。它会在正确的位置查找模板。


3
这个问题涉及 URLconf 错误,而不是模板。这就是为什么我对解决方法感到困惑(现在还是)。 - Rob Golding

0

我之前遇到了类似的错误信息,因为我的 URL 配置中定义了两个 logout 的 URL。

urlpatterns = [
    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
    url(r'^api/v1/', include(router.urls)),
    url(r'^logout/$', auth_views.logout, name='logout'),
    url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name='login'),
    url(r'^logout/$', auth_views.logout, {'template_name': 'logged_out.html'}, name='logout'),
]

0
我的解决方案是将django升级到最新版本: pip install --upgrade django==1.6.1 在此之前,请检查您安装的版本: pip freeze | grep Django - 我发现发布服务器上有一个旧版本,升级后解决了这个问题!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接