Special handling of multiple urls to one view with class based generic views
-
14-02-2021 - |
Question
I am converting a WordPress site to a django one. I need to preserve the url structure for old posts, but have a different structure for new posts. I've done this by creating the 2 urls, setting a date in settings.py, then setting the absolute url like so:
urls.py
url(r'^reviews/archives/(?P<pk>\d+)$', PostDetail.as_view(), name="oldpost_view"),
posts/urls.py
url(r'^(?P<slug>[-\w]+)$', PostDetail.as_view(), name="post_view"),
posts/models.py
@property
def is_old_post(self):
wp_date = settings.WP_ARCHIVE_DATE
if self.post_date.date() < wp_date:
return True
# return False
@models.permalink
def get_abs_url(self):
if self.is_old_post:
return ('oldpost_view', (), {
'pk': self.id,
}
)
else:
return ('post_view', [str(self.url_slug)])
I am using one view for the 2 urls:
class PostDetail(DetailView):
model = Post
slug_field = 'url_slug'
template_name = "posts/detail.html"
This all works great. Now, what I need to is prevent new posts from being rendered by the oldpost_view url and vice versa. I know I can override the "get" and use reverse for this but how can I tell which url the request came from? What is the most efficient and DRY way to do this?
La solution 2
Based on Issac Kelly's feedback I was able to solve my problem. Here's the updated views:
class PostDetail(DetailView):
model = Post
slug_field = 'post_name'
template_name = "posts/detail.html"
def OldPostView(request, pk):
post_name = get_object_or_404(Post, pk=pk).post_name
return redirect('post_view', slug=post_name, permanent=True)
I also updated my models to utilize the "post_name" field that WordPress has, then simplified my permalink:
@models.permalink
def get_abs_url(self):
return ('post_view', [str(self.post_name)])
Thanks Issac!
Autres conseils
If you don't follow my advice with the '301' status code above, here is how I would do it:
- Override the get method on the DetailView
- If the date is before CUTOFF_DATE, and request.path[:10] != "reviews/arc" --> Redirect (301)
- elseif date is after CUTOFF_DATE and request.path[:10] == "reviews/arc" --> redirect
Something roughly like that.