开发者

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(...)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜