| 1 |
from django import http |
|---|
| 2 |
from django.contrib.contenttypes.models import ContentType |
|---|
| 3 |
from django.contrib.sites.models import Site |
|---|
| 4 |
from django.core.exceptions import ObjectDoesNotExist |
|---|
| 5 |
|
|---|
| 6 |
def shortcut(request, content_type_id, object_id): |
|---|
| 7 |
"Redirect to an object's page based on a content-type ID and an object ID." |
|---|
| 8 |
# Look up the object, making sure it's got a get_absolute_url() function. |
|---|
| 9 |
try: |
|---|
| 10 |
content_type = ContentType.objects.get(pk=content_type_id) |
|---|
| 11 |
obj = content_type.get_object_for_this_type(pk=object_id) |
|---|
| 12 |
except ObjectDoesNotExist: |
|---|
| 13 |
raise http.Http404("Content type %s object %s doesn't exist" % (content_type_id, object_id)) |
|---|
| 14 |
try: |
|---|
| 15 |
absurl = obj.get_absolute_url() |
|---|
| 16 |
except AttributeError: |
|---|
| 17 |
raise http.Http404("%s objects don't have get_absolute_url() methods" % content_type.name) |
|---|
| 18 |
|
|---|
| 19 |
# Try to figure out the object's domain, so we can do a cross-site redirect |
|---|
| 20 |
# if necessary. |
|---|
| 21 |
|
|---|
| 22 |
# If the object actually defines a domain, we're done. |
|---|
| 23 |
if absurl.startswith('http://') or absurl.startswith('https://'): |
|---|
| 24 |
return http.HttpResponseRedirect(absurl) |
|---|
| 25 |
|
|---|
| 26 |
# Otherwise, we need to introspect the object's relationships for a |
|---|
| 27 |
# relation to the Site object |
|---|
| 28 |
object_domain = None |
|---|
| 29 |
opts = obj._meta |
|---|
| 30 |
|
|---|
| 31 |
# First, look for an many-to-many relationship to Site. |
|---|
| 32 |
for field in opts.many_to_many: |
|---|
| 33 |
if field.rel.to is Site: |
|---|
| 34 |
try: |
|---|
| 35 |
# Caveat: In the case of multiple related Sites, this just |
|---|
| 36 |
# selects the *first* one, which is arbitrary. |
|---|
| 37 |
object_domain = getattr(obj, field.name).all()[0].domain |
|---|
| 38 |
except IndexError: |
|---|
| 39 |
pass |
|---|
| 40 |
if object_domain is not None: |
|---|
| 41 |
break |
|---|
| 42 |
|
|---|
| 43 |
# Next, look for a many-to-one relationship to Site. |
|---|
| 44 |
if object_domain is None: |
|---|
| 45 |
for field in obj._meta.fields: |
|---|
| 46 |
if field.rel and field.rel.to is Site: |
|---|
| 47 |
try: |
|---|
| 48 |
object_domain = getattr(obj, field.name).domain |
|---|
| 49 |
except Site.DoesNotExist: |
|---|
| 50 |
pass |
|---|
| 51 |
if object_domain is not None: |
|---|
| 52 |
break |
|---|
| 53 |
|
|---|
| 54 |
# Fall back to the current site (if possible). |
|---|
| 55 |
if object_domain is None: |
|---|
| 56 |
try: |
|---|
| 57 |
object_domain = Site.objects.get_current().domain |
|---|
| 58 |
except Site.DoesNotExist: |
|---|
| 59 |
pass |
|---|
| 60 |
|
|---|
| 61 |
# If all that malarkey found an object domain, use it. Otherwise, fall back |
|---|
| 62 |
# to whatever get_absolute_url() returned. |
|---|
| 63 |
if object_domain is not None: |
|---|
| 64 |
protocol = request.is_secure() and 'https' or 'http' |
|---|
| 65 |
return http.HttpResponseRedirect('%s://%s%s' % (protocol, object_domain, absurl)) |
|---|
| 66 |
else: |
|---|
| 67 |
return http.HttpResponseRedirect(absurl) |
|---|