Strange behaviour because of the order of URLs in urls.py django behaviour
Question:
I am doing a mini blog assignment using Django for learning purpose. I noticed a strange behavior in django urls.py
when the order of lines is below I am able to make a successful GET call to http://127.0.0.1:8000/blog/blog/create
path('blog/create', views.BlogPostCreate.as_view(), name='blogpost-create'),
path('blog/<slug:slug>', views.BlogPostDetail.as_view(), name='blogpost-detail'),
but when the above lines are reveresed Then I start getting 404 error.
I am not sure why this error is happening. By just reading the Raised By in the message I did some shot in the air and the create form start loading. Can anyone explain the behavior? I am sure there must be some explanation for this.
Answers:
Because the paths are checked one by one, if you work with:
urlpatterns = [
path(
'blog/<slug:slug>', views.BlogPostDetail.as_view(), name='blogpost-detail'
),
path('blog/create', views.BlogPostCreate.as_view(), name='blogpost-create'),
]
it will indeed pick the BlogPostsDetail
view. Why? Because create
is a valid slug. It thus will "fire" the BlogPostDetail
view with slug='create'
. Since there is no BlogPost
with that slug, the view returns a 404.
But the URL dispatcher thus will enumerate over the patterns and fire the first one it finds that can fire. Since for blog/create
, the first path can fire, it will pick that one. The fact that there is another path that can fire makes not much sense.
That being said, personally I’m not a fan of paths that can overlap. You might want to make non-overlapping ones, like:
urlpatterns = [
path('blogs/create/', views.BlogPostCreate.as_view(), name='blogpost-create'),
path(
'blog/<slug:slug>/', views.BlogPostDetail.as_view(), name='blogpost-detail'
),
]
That way it is possible that a blog with create
as slug is picked, and people can also create BlogPost
s.
I am doing a mini blog assignment using Django for learning purpose. I noticed a strange behavior in django urls.py
when the order of lines is below I am able to make a successful GET call to http://127.0.0.1:8000/blog/blog/create
path('blog/create', views.BlogPostCreate.as_view(), name='blogpost-create'),
path('blog/<slug:slug>', views.BlogPostDetail.as_view(), name='blogpost-detail'),
but when the above lines are reveresed Then I start getting 404 error.
I am not sure why this error is happening. By just reading the Raised By in the message I did some shot in the air and the create form start loading. Can anyone explain the behavior? I am sure there must be some explanation for this.
Because the paths are checked one by one, if you work with:
urlpatterns = [
path(
'blog/<slug:slug>', views.BlogPostDetail.as_view(), name='blogpost-detail'
),
path('blog/create', views.BlogPostCreate.as_view(), name='blogpost-create'),
]
it will indeed pick the BlogPostsDetail
view. Why? Because create
is a valid slug. It thus will "fire" the BlogPostDetail
view with slug='create'
. Since there is no BlogPost
with that slug, the view returns a 404.
But the URL dispatcher thus will enumerate over the patterns and fire the first one it finds that can fire. Since for blog/create
, the first path can fire, it will pick that one. The fact that there is another path that can fire makes not much sense.
That being said, personally I’m not a fan of paths that can overlap. You might want to make non-overlapping ones, like:
urlpatterns = [
path('blogs/create/', views.BlogPostCreate.as_view(), name='blogpost-create'),
path(
'blog/<slug:slug>/', views.BlogPostDetail.as_view(), name='blogpost-detail'
),
]
That way it is possible that a blog with create
as slug is picked, and people can also create BlogPost
s.