Django URLs TypeError: view deve ser um chamável ou uma lista / tupla no caso de include ()

111

Depois de atualizar para Django 1.10, recebo o erro:

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

Meu urls.py é o seguinte:

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

O traceback completo é:

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
fonte
Se usarmos decoradores em vista e se não retornar nada. Neste caso também obtemos o erro acima. Recentemente, recebi este erro.
anjaneyulubatta505
@AnjaneyuluBatta sim, se um decorador não retornar uma visualização, ele retornará implicitamente None, o que causaria um TypeErrorigual acima.
Alasdair

Respostas:

257

Django 1.10 não permite mais que você especifique views como uma string (por exemplo 'myapp.views.home') em seus padrões de URL.

A solução é atualizar seu urls.pypara incluir o modo de exibição que pode ser chamado. Isso significa que você deve importar a visualização em seu urls.py. Se seus padrões de URL não têm nomes, agora é um bom momento para adicionar um, porque reverter com o caminho python pontilhado não funciona mais.

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

Se houver muitas visualizações, importá-las individualmente pode ser inconveniente. Uma alternativa é importar o módulo de visualizações do seu aplicativo.

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

Observe que usamos as myapp_viewse as auth_views, o que nos permite importar o views.pyde vários aplicativos sem que entrem em conflito.

Veja a documentação do despachante URL do Django para mais informações sobre urlpatterns.

Alasdair
fonte
E as visualizações baseadas em classe?
Rishabh Agrahari
2
Você nunca foi capaz de usar o caminho da string pontilhada para visualizações baseadas em classe, então eles não são relevantes para esta questão.
Alasdair
Desejo ver a mudança como essa vir com algum auxiliar (um script de migração), porque você não pode usar prefixo também. import_modulepode ajudá-lo a construir sua própria pesquisa como um wrapper para a string antiga, em um caso quando milhares de urls estão esperando por você para atualizá-los.
Sławomir Lenart
Você ainda terá que importar outros pacotes também - import de django.conf.urls import url. Por favor, corrija sua solução.
WebComer
1
@WebComer Eu não incluí a importação de url na pergunta / resposta porque eles permanecem os mesmos ao atualizar para o Django 1.10 (a menos que você tenha django.conf.urls.defaultsdo Django 1.5 ou anterior). Eu adicionei as importações conforme você pediu, mas não tenho certeza se isso é uma boa ideia, já que as importações mudam novamente no Django 2.0. Se você deseja saber as importações corretas, os documentos para sua versão do Django (por exemplo , 1.11 , 2.0 ) são o melhor lugar para procurar.
Alasdair
3

Esse erro significa apenas que myapp.views.homenão é algo que pode ser chamado, como uma função. Na verdade, é uma corda. Embora sua solução funcione no django 1.9, no entanto, ele lança um aviso dizendo que ele vai descontinuar a partir da versão 1.10, que é exatamente o que aconteceu. A solução anterior de @Alasdair importa as funções de visualização necessárias para o script por meio de from myapp import views as myapp_views ou from myapp.views import home, contact

hAcKnRoCk
fonte
1

Você também pode obter este erro se houver conflito de nomes entre uma visualização e um módulo. Recebi o erro ao distribuir meus arquivos de visualização na pasta de visualizações /views/view1.py, /views/view2.pye importei algum modelo chamado table.py em view2.py, que por acaso era o nome de uma visualização em view1.py. Portanto, nomear as funções de visualização v_table(request,id) ajudou.

binboavetonik
fonte
0

Seu código é

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

mude para o seguinte ao importar a include()função:

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