11

I am working with django 1.9 and I am currently coding - in Windows Command Prompt - python manage.py makemigrations and the error:

AttributeError: 'str' object has no attribute 'regex'

I have tried coding:

url(r'^$', 'firstsite.module.views.start', name="home"),
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name='login'),
url(r'^signup/$', 'exam.views.signup', name='signup'),
url(r'^signup/submit/$', 'exam.views.signup_submit', name='signup_submit')

in urls.py and the error is keeps coming up.

This is my first time coding in django, so my expertise is very limited. Thank you in advance.

This is the whole urls.py:

from django.conf.urls import patterns, include, url
import django
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = patterns('',
  # Examples:
  # url(r'^$', 'firstsite.views.home', name='home'),
  # url(r'^firstsite/', include('firstsite.foo.urls')),

  # Uncomment the admin/doc line below to enable admin documentation:
  # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

  # Uncomment the next line to enable the admin:
  #url(r'^admin/', include(admin.site.urls)),

  django.conf.urls.handler400,

  url(r'^$', 'firstsite.module.views.start', name="home"),
  url(r'^admin/', include(admin.site.urls)),
  url(r'^$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name='login'),
  url(r'^signup/$', 'exam.views.signup', name='signup'),
  url(r'^signup/submit/$', 'exam.views.signup_submit', name='signup_submit'),
  )
Alasdair
  • 298,606
  • 55
  • 578
  • 516
Hannah Wight
  • 131
  • 1
  • 3
  • 12
  • 3
    Can you show full traceback, then we can help you? – Zagorodniy Olexiy Jan 18 '16 at 11:26
  • Please show the whole urls.py as well. The problem could be the way you are defining `urlpatterns`, not in an individual `url()`. – Alasdair Jan 18 '16 at 11:31
  • 2
    Do you _really_ have this `django.conf.urls.handler400` line in the middle of your urls ??? If yes remove it, a `view` is not an `url`... – bruno desthuilliers Jan 18 '16 at 11:51
  • Also note you'll get a `RemovedInDjango110Warning: Support for string view arguments to url() is deprecated and will be removed in Django 1.10 (got django.contrib.auth.views.login). Pass the callable instead. url(r'^$', 'django.contrib.auth.views.login', name="login")`. Use `from django.contrib import auth` and `auth.views.login` instead. – SaeX Jan 18 '16 at 11:55

4 Answers4

11

Also make sure to remove the beginning empty url pattern--can be overlooked when migrating your urls.

urlpatterns = ['', # <== this blank element ('') produces the error.
    ...
]

tl;dr

For the curious, I found this out by adding a warning to the check_pattern_startswith_slash method in the django.core.checks.urls module:

def check_pattern_startswith_slash(pattern):
    """
    Check that the pattern does not begin with a forward slash.
    """
    if not hasattr(pattern, 'regex'):
        warning = Warning(
            "Invalid pattern '%s'" % pattern,
            id="urls.W002",
        )
        return [warning]

And, sure enough, I got a bunch of warnings like this:

?: (urls.W002) Invalid pattern ''
Alasdair
  • 298,606
  • 55
  • 578
  • 516
i41
  • 311
  • 2
  • 9
  • Django 1.10 will check for invalid objects in `urlpatterns`, and display a warning if it finds any. See [ticket 26440](https://code.djangoproject.com/ticket/26440). Thanks for the idea! – Alasdair May 03 '16 at 12:49
10

Firstly, remove the django.conf.urls.handler400 from the middle of the urlpatterns. It doesn't belong there, and is the cause of the error.

Once the error has been fixed, you can make a couple of changes to update your code for Django 1.8+

  1. Change urlpatterns to a list, instead of using patterns()

  2. Import the views (or view modules), instead of using strings in your urls()

  3. You are using the same regex for the start and login views. This means you won't be able to reach the login views. One fix would be to change the regex for the login view to something like ^login/$

Putting that together, you get something like:

from firstsite.module.views import start
from exam import views as exam_views
from django.contrib.auth import views as auth_views

urlpatterns = [
  url(r'^$', start, name="home"),
  url(r'^admin/', include(admin.site.urls)),
  url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name='login'),
  url(r'^signup/$', exam_views.signup, name='signup'),
  url(r'^signup/submit/$', exam_views.signup_submit, name='signup_submit'),
]
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • OP might want to fix the identical root patterns, as well. – Daniel Roseman Jan 18 '16 at 12:13
  • Thanks @DanielRoseman, I hadn't spotted that. I've updated the answer. – Alasdair Jan 18 '16 at 12:17
  • You had `'exam.views.signup'` in your question, so you should have an app `exam` in your project, which contains an `__init__.py` file. Do you? For us to be able to help you, you might need to update your question to include the file layout of your project. – Alasdair Jan 18 '16 at 13:35
  • Thanks @Alasdair for the help. However what does firstsite.module mean? An error keeps coming up no module named 'firstsite.module'. – Hannah Wight Jan 18 '16 at 13:49
  • Again, this is based on the urls.py in your question. You had `'firstsite.module.views.start'`, which suggests that you have a `views.py` inside the `firstsite/module` directory. – Alasdair Jan 18 '16 at 14:14
2

Remove the beginning empty Url patterns and also remove

django.conf.urls.handler400,    

from your urls.py this will solve your problem.

KernelPanic
  • 2,328
  • 7
  • 47
  • 90
Emil George James
  • 1,181
  • 1
  • 10
  • 20
0

For Django 2

from django.urls.resolvers import get_resolver, URLPattern, URLResolver

urls = get_resolver()

def if_none(value):
    if value:
        return value
    return ''

def print_urls(urls, parent_pattern=None):
    for url in urls.url_patterns:
        if isinstance(url, URLResolver):
            print_urls(url, if_none(parent_pattern) + if_none(str(url.pattern)))
        elif isinstance(url, URLPattern):
            print(f"{url} ({url.lookup_str})")
            print('----')
print_urls(urls)
Ysrninja
  • 129
  • 1
  • 2
  • 9