Wordpress to Django: Strategies Dealing with Wordpress Querystring URLs
Stable URLs are the foundation of valuable information on the web. As Tim Berners-Lee eloquently described it "Cool URIs Don't Change" and I thought I'd address a few strategies and code I'm using in MetaRho for maintaining stable URLs for content migrating from Wordpress.
Wordpress Querystring URLs
By default Wordpress uses querystrings for accessing content, passing the internal ID number of the post through the 'p' attribute like so...
http://<domain name>/index.php?p=<post id>
So for example calling post id 1 on mydomain.com would look like.
http://www.mydomain.com/index.php?p=1
Since best practice for Cool URIs and in Django is to use real URLs instead of Querystrings this presents a small problem. The easiest solution I found is to simply implement a decorator in Django that I put on the default index view to watch for incoming WordPress querystring URLs and query some extra field on the model for blog posts that holds the original WordPress ID number. Note I do NOT try to maintain ID numbers between posts as the better practice is to keep these opaque from the user.
I use the common strategy of keeping a one to many Model related to my posts to contain key value pairs for extra data. In my implementation I call that Model PostMeta and when I import content I just store the original WordPress ID number under a key 'wp_post_id'.
def wp_post_redirect(view_fn):
'''
Checks a request for a querystring item matching a WordPress
post request.
This is to enables url redirects for blog migrations from WordPress.
To use just decorate the view method for your default blog location.
'''
def decorator(request, *args, **kwargs):
wp_query = request.GET.get('p', None)
if wp_query:
try:
post = Post.objects.published().get(postmeta__key='wp_post_id',
postmeta__value=wp_query)
ar = post.pub_date.strftime("%Y/%m/%d").split('/')
ar.append(post.slug)
htr = HttpResponseRedirect(reverse('blog:post-detail', args=ar))
htr.status_code = 301 # This should reflect a 'Moved Permanently' code.
return htr
except Post.DoesNotExist:
raise Http404
return view_fn(request, *args, **kwargs)
return decorator
The decorator is fairly simple and just queries for posts with that meta key and redirects the user to the real URL with the proper status code or issues a 404 if no post is found.
It's important to note that this decorator needs to be put on the view used at the of the blog app as that is the equivalent behavior from WordPress.
In my next update I'll discuss a bit about designing Django URLs to deal with typical WordPress URL rewrite configurations.
