Django: reuse code for redirection on missing object
I have a site whose URLs look like
http://www.example.com/NY-2010/
http://www.example.com/NY-2010/location/
http://www.example.com/NY-2010/something-else/
http://www.example.com/Washington-2009/
http://www.example.com/Washington-2009/location/
http://www.example.com/Washington-2009/something-else/
and so on. There are various pages (like location) for various editions (like NY). I use URLconfs like
url(r'^(?P<edition>[\d]+\-[\w]+)/$', views.home),
url(r'^(?P<edition>[\d]+\-[\w]+)/location/$', views.location),
In each of the views I have to fetch the current edition. The fact is, if the edition name is wrong, I want to redirect to the latest edition. So I do something like
def home(request, edition):
try:
event = Edition.objects.get(name=edition)
except ObjectDoesNotExist:
return redirect(home, edition=Edition.latest())
# If event was found I go on here
def location(request, edition):
try:
event = Edition.object开发者_运维问答s.get(name=edition)
except ObjectDoesNotExist:
return redirect(home, edition=Edition.latest())
# If event was found I go on here
and so on. Of course there is some duplication that I'd like to minimize. I can think of two ways:
- use
get_objects_or_404()
and customize the 404 view, or - abstract the common part in a function.
The problem with both ways is that they do not allow me to do a proper redirect, that is, the URL will remain the same even if the view was changed. Is there a better way to handle these redirects?
EDIT It seems my question is not clear. In particular it is not clear what I mean by abstract the common part in a function. So, what I could do is the following
def get_edition_or_current(edition):
try:
event = Edition.objects.get(name=edition)
except ObjectDoesNotExist:
event = Edition.latest()
return event
def home(request, edition):
event = get_edition_or_current(edition)
# I go on with a valid event here
def location(request, edition):
event = get_edition_or_current(edition)
# I go on with a valid event here
In this way I can display the view for a proper event, but I cannot change the URL. To change the URL, the view must return a redirect. I cannot set the return value for the view from inside get_edition_or_current
.
So, how does Django implements get_object_or_404
? Well, it is simple, it raises an Http404 exception, and catches it later. But of course this only works for Http404 exceptions, because Django is instructed to catch them.
I think the simplest way to do this would be to create new utility function called get_object_or_redirect
in the same vein as get_object_or_404
. You could probably even copy the contents of get_object_or_404
from django.shortcuts as a starting point for your implementation, or just extract out what you have above.
EDIT: as noted in the comments, a redirect cannot be done via raising an "exception," so this really can't work the same as get_object_or_404.
After some more thought, I have found a solution. It is enough to
- use
get_object_or_404
- customize the 404 view, but not directly set it to the desired view. Rather, set it to a view which will send a redirect to the correct view.
Example
handler404 = views.error404
# Inside views
def error404(request):
return redirect(...)
精彩评论