Django URL Path Wildcard
In the event you restructure your website or migrate to a different platform, you may be left with many dead links that need to be handled, for user experience and SEO you do not want to throw a 404 error. Google does not know yet that your site has changed and knows of all your old links and will keep sending viewers there, so instead you should redirect to the new URL, your home page, or a landing page that lets the user know the link has been moved and you are working on it or it is permanently dead. In this post I assume your new site is a django application and there is a path prefix that is standard for your URLS (think index.php/link/to/your/post) that you wish to match and redirect.
Analyze Old URL's
Take a look at your old URLs, and from left to right after the domain name is the first section consistent? To see what I am talking about look at the links below
https://mysite.com/index.php/2020/05/my-old-article
https://mysite.com/index.php/2020/06/i-have-opinions-on-things
https://mysite.com/index.php/2021/02/my-opinions-have-changed
In this example we can see that every relative URL (the part after .com/
) starts with index.php.
Analyze New URL's
Next thing take a look at the URL paths in all of your urls.py files of your new site. Are there any that begin with index.php, if you restructured the URL's of your site to something new then my assumption is none of them do. If for some reason you do have a URL that begins with index.php, my guess is that you were trying to do that for backwards compatibility and this may not be the best way to solve your problem of handling your old URL's.
So assuming that none of your URL paths of your new django site begin with index.php we can key off of this and route any traffic that comes in with the url starting with mysite.com/index.php will be handled by a specific view.
Add Regex Path to urls.py
If you have multiple apps in your Django project, put it in the urls.py file that makes the most sense, but in this example since we are keying off index.php which is at the root of the path I will be putting it in the projects urls.py file.
from django.urls import re_path
from . import views
# Rest of imports here
urlpatterns = [
# Additional URL patterns
re_path(r'^index.php/.*$', views.redirect_noexist, name='redirect-nonexist'),
# Additional URL patterns
]
Taking a look here we first need to import re_path
from django.urls
.
The second line in my case is importing all of my views that I need, if your view (we will create later) is in a different file, make sure to import it.
Then in the URL patterns we will add a re_path with the following arguments:
-
r'^index.php/.*$'
This is the regular expression which matches any relative URL that starts with index.php. The key part here is the.*
which is the wildcardviews.redirect_noexist
I created a function based view and this is that function.name='redirect-nonexist'
And finally this is the name in django that it will be referenced under
If you are familiar with django the patter of the path should be fairly easy to understand, but again the key piece in all this is using re_path and .*
denoting a wildcard in the URL path.
Add View to Handle Path
Now we have the URL being routed to our view, we need to make a view. In this example I will simply redirect the browser to the home page and add a flash message letting the user know we are in the process of migrating to a new site and are working on getting this link working.
Because in my urls.py file I routed this to a function based view in views.py I will edit that file and add the following.
from django.shortcuts import redirect
from django.contrib import messages
# Other imports
# Other views
def redirect_noexist(request):
"""This function based view handles anyone coming from our old URL structure"""
message = 'Were sorry, this link is from our old URL structure we are working on getting it working. Please try again later.'
response = redirect('blog-home')
response.status_code = 307
messages.add_message(request, messages.INFO, message)
return response
Stepping through the code:
First come our imports, you may already have these imports in your file, but these are the ones required.
We define our function per the name in the urls.py file and take the request as an argument.
Then I define a variable to contain my message mainly for readability.
I then construct a redirect response to the route I want to send the users of my site to which in this case is named blog-home.
I then want to set the status code of that redirect to 307 indicating it is only temporary.
Then I add a flash message to the request object as an informational message, and I attach the text of my message that I previously defined. This is not required I just want the users to know I am working on it so if you don't have flash messages setup in your app don't worry about it.
And lastly I return the redirect response out of the view and to the browser.
Get Specific Content Instead of Blanket Redirection
You may be asking yourself, I have my old article in my database and want to display the article how can I retrieve it? The good news is you absolutely can! The unfortunate thing is I can't dive deep into specific examples because each site is unique in their URL structure and depending on the structure it can change the best way to solve this problem. More good news is I do have some high level ideas to get your brain thinking of things.
- Does your URLs have a unique SLUG in it? Does your legacy articles in your current database have a field for that slug?
- You could parse out the slug from the URL, do a database query for the slug which will return the object and you can do a permanent 301 redirect to the new URL path and render the article.
- Look at your old URL structure, what in it could you parse that is also in your database entries containing your old articles.
- Is there a primary key in both?
- Is the title in both?
- is there some combination of things like date and title?
You will likely be able to find some sort of pattern in the URL that you can then parse out and query the database to pull in your legacy article so you can render it. Then as a last resort if something is not found redirect to the home page.
And that is is! I hope this helped you understand how to do a wildcard URL in django and how it helps with site migrations or URL handling bulk URLs. If anything was unclear please leave a comment below and I can get back to you and update the article if things are unclear.