app/django/contrib/contenttypes/views.py
author Pawel Solyga <Pawel.Solyga@gmail.com>
Mon, 18 May 2009 19:37:38 +0200
changeset 2327 6c7d0fba105c
parent 323 ff1a9aa48cfd
permissions -rw-r--r--
Replace usage of feedparser for sanitizing html with new HtmlSanitizer module. HtmlSanitizer prevents from XSS attacks (Fixes issue 606).

from django import http
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.core.exceptions import ObjectDoesNotExist

def shortcut(request, content_type_id, object_id):
    "Redirect to an object's page based on a content-type ID and an object ID."
    # Look up the object, making sure it's got a get_absolute_url() function.
    try:
        content_type = ContentType.objects.get(pk=content_type_id)
        obj = content_type.get_object_for_this_type(pk=object_id)
    except ObjectDoesNotExist:
        raise http.Http404("Content type %s object %s doesn't exist" % (content_type_id, object_id))
    try:
        absurl = obj.get_absolute_url()
    except AttributeError:
        raise http.Http404("%s objects don't have get_absolute_url() methods" % content_type.name)

    # Try to figure out the object's domain, so we can do a cross-site redirect
    # if necessary.

    # If the object actually defines a domain, we're done.
    if absurl.startswith('http://') or absurl.startswith('https://'):
        return http.HttpResponseRedirect(absurl)

    # Otherwise, we need to introspect the object's relationships for a
    # relation to the Site object
    object_domain = None
    opts = obj._meta

    # First, look for an many-to-many relationship to Site.
    for field in opts.many_to_many:
        if field.rel.to is Site:
            try:
                # Caveat: In the case of multiple related Sites, this just
                # selects the *first* one, which is arbitrary.
                object_domain = getattr(obj, field.name).all()[0].domain
            except IndexError:
                pass
            if object_domain is not None:
                break

    # Next, look for a many-to-one relationship to Site.
    if object_domain is None:
        for field in obj._meta.fields:
            if field.rel and field.rel.to is Site:
                try:
                    object_domain = getattr(obj, field.name).domain
                except Site.DoesNotExist:
                    pass
                if object_domain is not None:
                    break

    # Fall back to the current site (if possible).
    if object_domain is None:
        try:
            object_domain = Site.objects.get_current().domain
        except Site.DoesNotExist:
            pass

    # If all that malarkey found an object domain, use it. Otherwise, fall back
    # to whatever get_absolute_url() returned.
    if object_domain is not None:
        protocol = request.is_secure() and 'https' or 'http'
        return http.HttpResponseRedirect('%s://%s%s' % (protocol, object_domain, absurl))
    else:
        return http.HttpResponseRedirect(absurl)