Django URLs TypeError:对于include(),视图必须是可调用的或列表/元组


111

升级到Django 1.10后,出现错误:

TypeError: view must be a callable or a list/tuple in the case of include().

我的urls.py如下:

from django.conf.urls import include, url

urlpatterns = [
    url(r'^$', 'myapp.views.home'),
    url(r'^contact/$', 'myapp.views.contact'),
    url(r'^login/$', 'django.contrib.auth.views.login'),
]

完整的回溯是:

Traceback (most recent call last):
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/utils/autoreload.py", line 226, in wrapper
    fn(*args, **kwargs)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 121, in inner_run
    self.check(display_num_errors=True)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/core/management/base.py", line 385, in check
    include_deployment_checks=include_deployment_checks,
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/core/management/base.py", line 372, in _run_checks
    return checks.run_checks(**kwargs)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/core/checks/registry.py", line 81, in run_checks
    new_errors = check(app_configs=app_configs)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/core/checks/urls.py", line 14, in check_url_config
    return check_resolver(resolver)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/core/checks/urls.py", line 24, in check_resolver
    for pattern in resolver.url_patterns:
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/utils/functional.py", line 35, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/urls/resolvers.py", line 310, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/utils/functional.py", line 35, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/urls/resolvers.py", line 303, in urlconf_module
    return import_module(self.urlconf_name)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/Users/alasdair/dev/urlproject/urlproject/urls.py", line 28, in <module>
    url(r'^$', 'myapp.views.home'),
  File "/Users/alasdair/.virtualenvs/django110/lib/python2.7/site-packages/django/conf/urls/__init__.py", line 85, in url
    raise TypeError('view must be a callable or a list/tuple in the case of include().')
TypeError: view must be a callable or a list/tuple in the case of include().

如果我们在视图上使用装饰器,并且不返回任何内容。在这种情况下,我们也会得到以上错误。最近我收到此错误。
anjaneyulubatta505'2013/

@AnjaneyuluBatta是的,如果装饰器未返回视图,则它隐式返回None,这将导致TypeError上述问题。
阿拉斯代尔

Answers:


257

Django 1.10不再允许您'myapp.views.home'在URL模式中将视图指定为字符串(例如)。

解决方案是更新您urls.py的视图以包含可调用的视图。这意味着您必须在中导入视图urls.py。如果您的URL模式没有名称,那么现在是添加名称的好时机,因为用虚线python路径进行反向操作不再起作用。

from django.conf.urls import include, url

from django.contrib.auth.views import login
from myapp.views import home, contact

urlpatterns = [
    url(r'^$', home, name='home'),
    url(r'^contact/$', contact, name='contact'),
    url(r'^login/$', login, name='login'),
]

如果有很多视图,则不方便分别导入它们。一种替代方法是从您的应用程序导入视图模块。

from django.conf.urls import include, url

from django.contrib.auth import views as auth_views
from myapp import views as myapp_views

urlpatterns = [
    url(r'^$', myapp_views.home, name='home'),
    url(r'^contact/$', myapp_views.contact, name='contact'),
    url(r'^login/$', auth_views.login, name='login'),
]

请注意,我们已经使用as myapp_viewsas auth_views,这允许我们views.py从多个应用程序导入,而不会发生冲突。

有关的更多信息,请参见Django URL调度程序文档urlpatterns


基于类的视图呢?
Rishabh Agrahari

2
对于基于类的视图,您永远无法使用点分隔的字符串路径,因此它们与该问题无关。
阿拉斯代尔

我希望看到这样的更改带有一些帮助程序(正在迁移的脚本),因为您也无法使用前缀。import_module在成千上万的网址等待您更新它们的情况下,可以帮助您建立自己的查找作为旧式字符串的包装。
斯瓦沃米尔Lenart

您仍然还必须导入其他软件包-从django.conf.urls导入url。请解决您的解决方案。
WebComer

1
@WebComer我没有在问题/答案中包含url导入,因为升级到Django 1.10时它们保持不变(除非您django.conf.urls.defaults从Django 1.5或更早版本开始)。我已经按照您的要求添加了导入,但是我不确定这是一个好主意,因为导入在Django 2.0中再次更改。如果你想知道正确的进口,那么文档为你的Django的版本(如1.112.0)是这方面的最好的地方。
阿拉斯代尔

3

该错误仅意味着myapp.views.home不能调用它,就像函数一样。它实际上是一个字符串。当您的解决方案在django 1.9中运行时,它仍然发出警告,说它将从版本1.10开始弃用,这就是发生的一切。通过@Alasdair先前的溶液中导入必要的视图函数到脚本通过任一 from myapp import views as myapp_viewsfrom myapp.views import home, contact


1

如果视图和模块的名称冲突,也可能会出现此错误。我将我的视图文件分发到views文件夹下,/views/view1.py, /views/view2.py并在view2.py中导入了一个名为table.py的模型时遇到了错误,该模型恰巧是view1.py中的视图名称。因此,命名视图功能 v_table(request,id) 很有帮助。


0

您的代码是

urlpatterns = [
    url(r'^$', 'myapp.views.home'),
    url(r'^contact/$', 'myapp.views.contact'),
    url(r'^login/$', 'django.contrib.auth.views.login'),
]

在导入include()功能时将其更改为以下内容:

urlpatterns = [
    url(r'^$', views.home),
    url(r'^contact/$', views.contact),
    url(r'^login/$', views.login),
]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.