Adresy URL Django TypeError: widok musi być wywoływalny lub lista / krotka w przypadku include ()

111

Po aktualizacji do Django 1.10 otrzymuję błąd:

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

Mój adres urls.py wygląda następująco:

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

Pełne dane śledzenia to:

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
źródło
Jeśli używamy dekoratorów na widoku i jeśli nic nie zwracamy. W tym przypadku również otrzymujemy powyższy błąd. ostatnio dostałem ten błąd.
anjaneyulubatta505
@AnjaneyuluBatta tak, jeśli dekorator nie zwraca widoku, to niejawnie zwraca None, co spowodowałoby TypeErrorjak powyżej.
Alasdair

Odpowiedzi:

257

Django 1.10 nie pozwala już na określanie widoków jako łańcucha (np. 'myapp.views.home') We wzorcach URL.

Rozwiązaniem jest aktualizacja, urls.pyaby uwzględnić widok wywoływalny. Oznacza to, że musisz zaimportować widok do swojego urls.py. Jeśli twoje wzorce adresów URL nie mają nazw, teraz jest dobry moment, aby je dodać, ponieważ odwracanie za pomocą kropkowanej ścieżki Pythona już nie działa.

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

Jeśli istnieje wiele widoków, importowanie ich pojedynczo może być niewygodne. Alternatywą jest zaimportowanie modułu widoków z aplikacji.

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

Zauważ, że użyliśmy as myapp_viewsi as auth_views, co pozwala nam importować views.pyz wielu aplikacji bez ich kolizji.

Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą rozsyłania adresów URL Djangourlpatterns .

Alasdair
źródło
A co z widokami klasowymi?
Rishabh Agrahari
2
Nigdy nie byłeś w stanie użyć kropkowanej ścieżki ciągu dla widoków opartych na klasach, więc nie są one istotne dla tego pytania.
Alasdair
Chciałbym, aby taka zmiana przyszła z pomocą jakiegoś pomocnika (skryptu migracji), ponieważ nie możesz również użyć prefiksu. import_modulemoże pomóc w zbudowaniu własnego wyszukiwania jako opakowania dla starego ciągu znaków w przypadku, gdy tysiące adresów URL czekają na ich aktualizację.
Sławomir Lenart
Nadal musisz importować inne pakiety - importuj z django.conf.urls importuj url. Popraw swoje rozwiązanie.
WebComer
1
@WebComer Nie uwzględniłem importu adresu URL w pytaniu / odpowiedzi, ponieważ pozostają takie same podczas aktualizacji do Django 1.10 (chyba że masz django.conf.urls.defaultsz Django 1.5 lub wcześniejszego). Dodałem importy zgodnie z twoją prośbą, ale nie jestem pewien, czy to dobry pomysł, ponieważ import zmienia się ponownie w Django 2.0. Jeśli chcesz wiedzieć, jakie są prawidłowe importy, najlepszym miejscem do przeglądania są dokumenty Twojej wersji Django (np. 1.11 , 2.0 ).
Alasdair
3

Ten błąd oznacza po prostu, że myapp.views.homenie można tego nazwać, jak funkcja. W rzeczywistości jest to ciąg. Chociaż Twoje rozwiązanie działa w django 1.9, niemniej jednak wyświetla ostrzeżenie, że będzie ono przestarzałe od wersji 1.10, co jest dokładnie tym, co się stało. Poprzednie rozwiązanie autorstwa @Alasdair importuje niezbędne funkcje widoku do skryptu za pomocą from myapp import views as myapp_views lub from myapp.views import home, contact

hAcKnRoCk
źródło
1

Możesz również otrzymać ten błąd, jeśli masz zderzenie nazw widoku i modułu. Otrzymałem błąd, kiedy rozpowszechniłem moje pliki widoku w folderze views /views/view1.py, /views/view2.pyi zaimportowałem model o nazwie table.py do view2.py, który był nazwą widoku w view1.py. Tak więc nazwanie widoku jest v_table(request,id) pomocne.

binboavetonik
źródło
0

Twój kod to

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

zmień go na następujący podczas importowania include()funkcji:

urlpatterns = [
    url(r'^$', views.home),
    url(r'^contact/$', views.contact),
    url(r'^login/$', views.login),
]
Nishant Soni
źródło