1 from django.core.exceptions import ObjectDoesNotExist |
1 from django import http |
2 from django.template import Context, RequestContext, loader |
2 from django.template import Context, RequestContext, loader |
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) |
|
68 |
3 |
69 def page_not_found(request, template_name='404.html'): |
4 def page_not_found(request, template_name='404.html'): |
70 """ |
5 """ |
71 Default 404 handler, which looks for the requested URL in the redirects |
6 Default 404 handler. |
72 table, redirects if found, and displays 404 page if not redirected. |
|
73 |
7 |
74 Templates: `404.html` |
8 Templates: `404.html` |
75 Context: |
9 Context: |
76 request_path |
10 request_path |
77 The path of the requested URL (e.g., '/app/pages/bad_page/') |
11 The path of the requested URL (e.g., '/app/pages/bad_page/') |
86 Templates: `500.html` |
20 Templates: `500.html` |
87 Context: None |
21 Context: None |
88 """ |
22 """ |
89 t = loader.get_template(template_name) # You need to create a 500.html template. |
23 t = loader.get_template(template_name) # You need to create a 500.html template. |
90 return http.HttpResponseServerError(t.render(Context({}))) |
24 return http.HttpResponseServerError(t.render(Context({}))) |
|
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) |