URL de Django TypeError: la vista debe ser invocable o una lista / tupla en el caso de include ()

111

Después de actualizar a Django 1.10, aparece el error:

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

Mi urls.py es el siguiente:

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'),
]

El rastreo completo es:

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().
Alasdair
fuente
Si usamos decoradores a la vista y si no devuelve nada. En este caso también obtenemos el error anterior. Recientemente recibí este error.
anjaneyulubatta505
@AnjaneyuluBatta sí, si un decorador no devuelve una vista, devuelve implícitamente None, lo que provocaría un TypeErrorcomo el anterior.
Alasdair

Respuestas:

257

Django 1.10 ya no le permite especificar vistas como una cadena (por ejemplo 'myapp.views.home') en sus patrones de URL.

La solución es actualizar su urls.pypara incluir la vista invocable. Esto significa que debe importar la vista en su urls.py. Si sus patrones de URL no tienen nombres, ahora es un buen momento para agregar uno, porque invertir con la ruta de Python punteada ya no funciona.

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'),
]

Si hay muchas vistas, importarlas individualmente puede resultar inconveniente. Una alternativa es importar el módulo de vistas desde su aplicación.

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'),
]

Tenga en cuenta que hemos utilizado as myapp_viewsy as auth_views, lo que nos permite importar views.pydesde varias aplicaciones sin que entren en conflicto.

Consulte los documentos del despachador de URL de Django para obtener más información sobre urlpatterns.

Alasdair
fuente
¿Qué pasa con las vistas basadas en clases?
Rishabh Agrahari
2
Nunca ha podido utilizar la ruta de la cadena de puntos para las vistas basadas en clases, por lo que no son relevantes para esta pregunta.
Alasdair
Deseo que el cambio como este venga con algún ayudante (un script de migración), porque no puedes usar el prefijo también. import_modulepodría ayudarlo a crear su propia búsqueda como contenedor para la cadena antigua, en el caso de que miles de URL estén esperando que las actualice.
Sławomir Lenart
También tiene que importar otros paquetes: importar desde la url de importación django.conf.urls. Corrija su solución.
WebComer
1
@WebComer No incluí la importación de url en la pregunta / respuesta porque siguen siendo las mismas al actualizar a Django 1.10 (a menos que tenga django.conf.urls.defaultsdesde Django 1.5 o anterior). Agregué las importaciones como me pidió, pero no estoy seguro de que sea una buena idea, ya que las importaciones cambian nuevamente en Django 2.0. Si desea conocer las importaciones correctas, los documentos para su versión de Django (por ejemplo , 1.11 , 2.0 ) son el mejor lugar para buscar.
Alasdair
3

Este error solo significa que myapp.views.homeno es algo que se pueda llamar, como una función. De hecho, es una cuerda. Si bien su solución funciona en django 1.9, sin embargo, arroja una advertencia que dice que esto se desaprobará a partir de la versión 1.10, que es exactamente lo que sucedió. La solución anterior de @Alasdair importa las funciones de visualización necesarias en el script a través de from myapp import views as myapp_views o from myapp.views import home, contact

hAcKnRoCk
fuente
1

También puede obtener este error si tiene un conflicto de nombres entre una vista y un módulo. Tengo el error cuando distribuyo mis archivos de vista en la carpeta de vistas, /views/view1.py, /views/view2.pye importé un modelo llamado table.py en view2.py que resultó ser el nombre de una vista en view1.py. Así que nombrar las funciones de vista como v_table(request,id) ayudado.

binboavetonik
fuente
0

Tu código es

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

cámbielo a lo siguiente mientras está importando la include()función:

urlpatterns = [
    url(r'^$', views.home),
    url(r'^contact/$', views.contact),
    url(r'^login/$', views.login),
]
Nishant Soni
fuente