Joshua Schlichting
Joshua Schlichting

Reputation: 3450

Django urls help - not able to access view

Let me start by saying I'm new to Django and I realize this seems simple (and I'm hoping it is).

I'm following a tutorial that is taking me through the basic set up of a simple Django site, and I've found myself stuck at a point where I'm simply calling on a new view the tutorial just had me add. (for those interested, the tutorial is here https://overiq.com/django/1.10/views-and-urlconfs-in-django/)

So, I've got my server up and running, and I'm trying to access

http://127.0.0.1:8000/blog/time/

When I try to access that view, I get the error:

Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order:

^blog ^time/$ [name='todays_time']
^blog ^$ [name='blog_index']
^admin/

The current path, blog/time/, didn't match any of these.

Here is the layout of my Django project:

Django project layout

My mysite's urls.py file looks like this:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^blog/', include('blog.urls')),
    url(r'^admin/', admin.site.urls),
]

My blog package's urls.py file looks like this:

from django.conf.urls import url
from blog import views

urlpatterns = [
    url(r'^time/$', views.today_is, name='todays_time'),
    url(r'^$', views.index, name='blog_index'),
]

my blog package's views.py looks like this:

from django.http import HttpResponse
import datetime

def index(request):
    return HttpResponse("Hello Django!!!")

def today_is(request):
    now = datetime.datetime.now()
    html = '''
            <html>
                <body>
                    Current date and time: {0}
                </body>
            </html>
            '''.format(now)
    return HttpResponse(html)

I can successfully go to

http://127.0.0.1:8000/blog

and see the response from index() as "Hello Django!!!" in my browser. So with that I was expecting

http://127.0.0.1:8000/blog/time/

to work just fine, but it doesn't, and attempting to view that is what yields the error I shared above.

Can anyone point me in the right direction here? I'd appreciate it! Thanks, everyone!

NOTE: I can provide more details, screen grabs, or code snippets as needed, just let me know what I might be missing here!

Upvotes: 4

Views: 2950

Answers (3)

John Gilmore
John Gilmore

Reputation: 456

^ (caret) is regex (regular expressions) for matching the start of a string. However, the way it's displayed in angular's 404 page is a little strange. You'll often see "^ ^" or caret space caret, and otherwise repeated carets in the urlpatterns listed. On the face of it, that makes it utterly impossible to match any string since, as has been pointed out, a string can't start in two different places.

What's going on is django is matching things in hierarchical order, and the pattern that's displayed as:

"^blog ^time/$"

above is actually TWO patterns:

"^blog"

and then:

"^time/$"

This is completely normal, if confusingly displayed, and is the expected way to process an "include" statement here. It's just not getting displayed with a visible delimiter.

To test this, notice that any include directive that wasn't matched in the first part doesn't get expanded in the 404 page. I noticed this when trying to get the rest-auth package to work:

url(r'admin/', admin.site.urls, name='admin'),                     
url(r'^$', views.api_root, name='api_root'),
url(r'^auth/', include('rest_auth.urls')),
url(r'^auth/', include('rest_auth.registration.urls')),

If I entered a url begining with "admin" then the admin block is shown expanded in the 404 page, but I can't see what urls might be valid if starting with "auth", and the 'auth' urls are displayed as bare (though repeated, 'cause there's two of them). If I enter an invalid URL begining with "auth/" then the opposite happens.

You may need to have more than one child urlpattern to see that effect though.

Django will remove the matching portion of the url before attempting to match child urlpatterns. This is why the seemingly impossible URL pattern given above CAN match a valid string.

If I have to guess why it wasn't working, it's probably because the first pattern there ("^blog") doesn't have a trailing "/", and so the correct URL would be "blogtime/". (This doesn't match the source you gave, did you change something?)

That probably isn't what you wanted. Add the trailing "/" to blog, and double check your trailing / on the url, and you're probably good to go.

Incidentally, you DO want the trailing "$". It will prevent urls like /blog/time/'drop table users;--' from resolving. Not that they'd do anything, django's pretty robust at this point I think, but it's still good practice. I assume django would try to parse them as parameters to pass to the view, though I haven't investigated that.

Upvotes: 0

Coder949
Coder949

Reputation: 1007

This would be correct as @LeLouch mentioned:

url(r'time/', views.today_is, name='todays_time')

Why do you start your regular expression two times with ^ ? You can only start it one time and end it one time. That is why it is showing:

^blog ^time/$ [name='todays_time']

When you remove the ^ it starts only one time and has not two beginnings and one ending. In your blog.urls you should just continue the regular expression. You break it with two times using ^.

When you removed it, it should show ^blog/time/$. The same thing is the problem for ^blog ^$ [name='blog_index'].

Upvotes: 1

LeLouch
LeLouch

Reputation: 611

your trying to access /blog/time but your url is blog/^time

urlpatterns = [
    #you have a carrot in here
    url(r'^time/$', views.today_is, name='todays_time'), 
    #it should be 
    url(r'time/', views.today_is, name='todays_time'),

]

thats why it can't find your url

Upvotes: 1

Related Questions