|
1 """ |
|
2 This module collects helper functions and classes that "span" multiple levels |
|
3 of MVC. In other words, these functions/classes introduce controlled coupling |
|
4 for convenience's sake. |
|
5 """ |
|
6 |
|
7 from django.template import loader |
|
8 from django.http import HttpResponse, Http404 |
|
9 from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect |
|
10 from django.db.models.manager import Manager |
|
11 from django.db.models.query import QuerySet |
|
12 from django.core import urlresolvers |
|
13 |
|
14 def render_to_response(*args, **kwargs): |
|
15 """ |
|
16 Returns a HttpResponse whose content is filled with the result of calling |
|
17 django.template.loader.render_to_string() with the passed arguments. |
|
18 """ |
|
19 httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)} |
|
20 return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs) |
|
21 |
|
22 def redirect(to, *args, **kwargs): |
|
23 """ |
|
24 Returns an HttpResponseRedirect to the apropriate URL for the arguments |
|
25 passed. |
|
26 |
|
27 The arguments could be: |
|
28 |
|
29 * A model: the model's `get_absolute_url()` function will be called. |
|
30 |
|
31 * A view name, possibly with arguments: `urlresolvers.reverse()` will |
|
32 be used to reverse-resolve the name. |
|
33 |
|
34 * A URL, which will be used as-is for the redirect location. |
|
35 |
|
36 By default issues a temporary redirect; pass permanent=True to issue a |
|
37 permanent redirect |
|
38 """ |
|
39 if kwargs.pop('permanent', False): |
|
40 redirect_class = HttpResponsePermanentRedirect |
|
41 else: |
|
42 redirect_class = HttpResponseRedirect |
|
43 |
|
44 # If it's a model, use get_absolute_url() |
|
45 if hasattr(to, 'get_absolute_url'): |
|
46 return redirect_class(to.get_absolute_url()) |
|
47 |
|
48 # Next try a reverse URL resolution. |
|
49 try: |
|
50 return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs)) |
|
51 except urlresolvers.NoReverseMatch: |
|
52 # If this doesn't "feel" like a URL, re-raise. |
|
53 if '/' not in to and '.' not in to: |
|
54 raise |
|
55 |
|
56 # Finally, fall back and assume it's a URL |
|
57 return redirect_class(to) |
|
58 |
|
59 def _get_queryset(klass): |
|
60 """ |
|
61 Returns a QuerySet from a Model, Manager, or QuerySet. Created to make |
|
62 get_object_or_404 and get_list_or_404 more DRY. |
|
63 """ |
|
64 if isinstance(klass, QuerySet): |
|
65 return klass |
|
66 elif isinstance(klass, Manager): |
|
67 manager = klass |
|
68 else: |
|
69 manager = klass._default_manager |
|
70 return manager.all() |
|
71 |
|
72 def get_object_or_404(klass, *args, **kwargs): |
|
73 """ |
|
74 Uses get() to return an object, or raises a Http404 exception if the object |
|
75 does not exist. |
|
76 |
|
77 klass may be a Model, Manager, or QuerySet object. All other passed |
|
78 arguments and keyword arguments are used in the get() query. |
|
79 |
|
80 Note: Like with get(), an MultipleObjectsReturned will be raised if more than one |
|
81 object is found. |
|
82 """ |
|
83 queryset = _get_queryset(klass) |
|
84 try: |
|
85 return queryset.get(*args, **kwargs) |
|
86 except queryset.model.DoesNotExist: |
|
87 raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) |
|
88 |
|
89 def get_list_or_404(klass, *args, **kwargs): |
|
90 """ |
|
91 Uses filter() to return a list of objects, or raise a Http404 exception if |
|
92 the list is empty. |
|
93 |
|
94 klass may be a Model, Manager, or QuerySet object. All other passed |
|
95 arguments and keyword arguments are used in the filter() query. |
|
96 """ |
|
97 queryset = _get_queryset(klass) |
|
98 obj_list = list(queryset.filter(*args, **kwargs)) |
|
99 if not obj_list: |
|
100 raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) |
|
101 return obj_list |