views.py 3.3 KB

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