| 3 | | from django.contrib.contenttypes.models import ContentType |
|---|
| 4 | | from django.contrib.sites.models import Site |
|---|
| 5 | | from django import http |
|---|
| 6 | | |
|---|
| 7 | | def shortcut(request, content_type_id, object_id): |
|---|
| 8 | | "Redirect to an object's page based on a content-type ID and an object ID." |
|---|
| 9 | | # Look up the object, making sure it's got a get_absolute_url() function. |
|---|
| 10 | | try: |
|---|
| 11 | | content_type = ContentType.objects.get(pk=content_type_id) |
|---|
| 12 | | obj = content_type.get_object_for_this_type(pk=object_id) |
|---|
| 13 | | except ObjectDoesNotExist: |
|---|
| 14 | | raise http.Http404, "Content type %s object %s doesn't exist" % (content_type_id, object_id) |
|---|
| 15 | | try: |
|---|
| 16 | | absurl = obj.get_absolute_url() |
|---|
| 17 | | except AttributeError: |
|---|
| 18 | | raise http.Http404, "%s objects don't have get_absolute_url() methods" % content_type.name |
|---|
| 19 | | |
|---|
| 20 | | # Try to figure out the object's domain, so we can do a cross-site redirect |
|---|
| 21 | | # if necessary. |
|---|
| 22 | | |
|---|
| 23 | | # If the object actually defines a domain, we're done. |
|---|
| 24 | | if absurl.startswith('http://') or absurl.startswith('https://'): |
|---|
| 25 | | return http.HttpResponseRedirect(absurl) |
|---|
| 26 | | |
|---|
| 27 | | object_domain = None |
|---|
| 28 | | |
|---|
| 29 | | # Otherwise, we need to introspect the object's relationships for a |
|---|
| 30 | | # relation to the Site object |
|---|
| 31 | | opts = obj._meta |
|---|
| 32 | | |
|---|
| 33 | | # First, look for an many-to-many relationship to sites |
|---|
| 34 | | for field in opts.many_to_many: |
|---|
| 35 | | if field.rel.to is Site: |
|---|
| 36 | | try: |
|---|
| 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) |
|---|
| | 25 | |
|---|
| | 26 | def shortcut(request, content_type_id, object_id): |
|---|
| | 27 | # TODO: Remove this in Django 2.0. |
|---|
| | 28 | # This is a legacy view that depends on the contenttypes framework. |
|---|
| | 29 | # The core logic was moved to django.contrib.contenttypes.views after |
|---|
| | 30 | # Django 1.0, but this remains here for backwards compatibility. |
|---|
| | 31 | # Note that the import is *within* this function, rather than being at |
|---|
| | 32 | # module level, because we don't want to assume people have contenttypes |
|---|
| | 33 | # installed. |
|---|
| | 34 | from django.contrib.contenttypes.views import shortcut as real_shortcut |
|---|
| | 35 | return real_shortcut(request, content_type_id, object_id) |
|---|