URL Django TypeError: la vue doit être appelable ou une liste / un tuple dans le cas de include ()

111

Après la mise à niveau vers Django 1.10, j'obtiens l'erreur:

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

Mon urls.py est le suivant:

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

Le suivi complet est:

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
la source
Si nous utilisons des décorateurs à vue et si cela ne renvoie rien. Dans ce cas également, nous obtenons l'erreur ci-dessus. récemment, j'ai eu cette erreur.
anjaneyulubatta505
@AnjaneyuluBatta oui, si un décorateur ne renvoie pas de vue alors il retourne implicitement None, ce qui provoquerait un TypeErrorcomme ci-dessus.
Alasdair

Réponses:

257

Django 1.10 ne vous permet plus de spécifier des vues sous forme de chaîne (par exemple 'myapp.views.home') dans vos modèles d'URL.

La solution consiste à mettre à jour votre urls.pypour inclure la vue appelable. Cela signifie que vous devez importer la vue dans votre fichier urls.py. Si vos modèles d'URL n'ont pas de noms, le moment est venu d'en ajouter un, car l'inversion avec le chemin python en pointillé ne fonctionne plus.

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

S'il existe de nombreuses vues, les importer individuellement peut être peu pratique. Une alternative consiste à importer le module de vues depuis votre application.

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

Notez que nous avons utilisé as myapp_viewset as auth_views, ce qui nous permet d'importer views.pydes applications à partir de plusieurs applications sans qu'elles ne s'affrontent.

Consultez la documentation du répartiteur d'URL Django pour plus d'informations sur urlpatterns.

Alasdair
la source
Qu'en est-il des vues basées sur les classes?
Rishabh Agrahari
2
Vous n'avez jamais été en mesure d'utiliser le chemin de chaîne en pointillé pour les vues basées sur les classes, elles ne sont donc pas pertinentes pour cette question.
Alasdair
Je souhaite que le changement comme celui-ci soit accompagné d'un assistant (un script de migration), car vous ne pouvez pas non plus utiliser le préfixe. import_modulepourrait vous aider à créer votre propre recherche en tant que wrapper pour la chaîne à l'ancienne, dans le cas où des milliers d'urls attendent que vous les mettiez à jour.
Sławomir Lenart
Vous devez également importer d'autres packages - importez depuis django.conf.urls import url. Veuillez corriger votre solution.
WebComer
1
@WebComer Je n'ai pas inclus l'importation d'url dans la question / réponse car elles restent les mêmes lors de la mise à niveau vers Django 1.10 (à moins que vous ne l'ayez django.conf.urls.defaultsdepuis Django 1.5 ou une version antérieure). J'ai ajouté les importations comme vous l'avez demandé, mais je ne suis pas sûr que ce soit une bonne idée, car les importations changent à nouveau dans Django 2.0. Si vous voulez connaître les importations correctes, alors la documentation de votre version de Django (par exemple 1.11 , 2.0 ) est le meilleur endroit pour chercher.
Alasdair
3

Cette erreur signifie simplement que ce myapp.views.homen'est pas quelque chose qui peut être appelé, comme une fonction. C'est une chaîne en fait. Bien que votre solution fonctionne dans django 1.9, elle lance néanmoins un avertissement indiquant que cela deviendra obsolète à partir de la version 1.10, ce qui est exactement ce qui s'est passé. La solution précédente de @Alasdair importe les fonctions d'affichage nécessaires dans le script via from myapp import views as myapp_views ou from myapp.views import home, contact

hAcKnRoCk
la source
1

Vous pouvez également obtenir cette erreur si vous avez un conflit de nom entre une vue et un module. J'ai l'erreur lorsque je distribue mes fichiers de vue dans le dossier de vues /views/view1.py, /views/view2.pyet que j'ai importé un modèle nommé table.py dans view2.py qui se trouvait être le nom d'une vue dans view1.py. Donc nommer les fonctions de vue comme v_table(request,id) aidé.

binboavetonik
la source
0

Votre code est

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

changez-le en suivant lorsque vous importez la include()fonction:

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