brandondavid
brandondavid

Reputation: 200

Django Identical URL Pattern in two Separate Apps Conflict

(Django v 1.10.4) I'm trying to use two separate apps who's url prefix is the root of the site (I'm migrating to django from another site and need to maintain the existing url structure). The two apps/models in question are "artistbio/Bio" and "pages/BasicPage". Currently I have the url patterns in the main url config (originally they were in their own respective url.py files but the issue I have is the same either way):

from django.conf.urls import include, url
from django.contrib import admin
from django.conf import settings
from artistbio.views import BioDetail
from pages.views import PageDetail


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^(?P<slug>[\w\-]+)/', PageDetail.as_view()),
    url(r'^(?P<slug>[-\w]+)/', BioDetail.as_view(), name='bio-detail'),

Everything I've read (and all my experience thus far) has shown that Django will try to match the request against each URL pattern before giving either a "did not match any url patterns" error or a "404 not found" error if the requested object truly doesn't exist. But now when both patterns are together as listed above, when I request a Bio object via BioDetail it tries to match against the URL pattern for PageDetail and gives me a 404 error (which makes sense) but it also seems to mean that Django never moves on to the next URL pattern where it would certainly be a match. If I switch them, and put the BioDetail pattern above the PageDetail pattern, as expected I then have access to Bio objects but not Page objects.

I've read every applicable StackOverflow entry I could find, have read all the official docs and referenced Django Unleashed but still seem to be missing the solution!

Upvotes: 0

Views: 825

Answers (1)

Antwane
Antwane

Reputation: 22688

From Django documentation:

When a user requests a page from your Django-powered site, this is the algorithm the system follows to determine which Python code to execute:

  1. Django determines the root URLconf module to use. Ordinarily, this is the value of the ROOT_URLCONF setting, but if the incoming HttpRequest object has a urlconf attribute (set by middleware), its value will be used in place of the ROOT_URLCONF setting.
  2. Django loads that Python module and looks for the variable urlpatterns. This should be a Python list of django.conf.urls.url() instances.
  3. Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL.
  4. Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function (or a class-based view). [...]

Focus on point 3: Django stop to process urlpatterns variable as soon as a regexp validate the current URL. It calls the view, and if that views return a 404, the error is returned to the client.

Django will not continue to match the url with following patterns if a view returned a 404.

So basically, to fix your issue, you will have to write a view that match the URL, analyze the slug and try to get the corresponding Page or Bio (in this order). But I suggest you to plan a migration to a system where Pages and Bio have their own view to display content.

Upvotes: 3

Related Questions