|
1 from django.template import loader, RequestContext |
|
2 from django.http import Http404, HttpResponse |
|
3 from django.core.xheaders import populate_xheaders |
|
4 from django.core.paginator import QuerySetPaginator, InvalidPage |
|
5 from django.core.exceptions import ObjectDoesNotExist |
|
6 |
|
7 def object_list(request, queryset, paginate_by=None, page=None, |
|
8 allow_empty=True, template_name=None, template_loader=loader, |
|
9 extra_context=None, context_processors=None, template_object_name='object', |
|
10 mimetype=None): |
|
11 """ |
|
12 Generic list of objects. |
|
13 |
|
14 Templates: ``<app_label>/<model_name>_list.html`` |
|
15 Context: |
|
16 object_list |
|
17 list of objects |
|
18 is_paginated |
|
19 are the results paginated? |
|
20 results_per_page |
|
21 number of objects per page (if paginated) |
|
22 has_next |
|
23 is there a next page? |
|
24 has_previous |
|
25 is there a prev page? |
|
26 page |
|
27 the current page |
|
28 next |
|
29 the next page |
|
30 previous |
|
31 the previous page |
|
32 pages |
|
33 number of pages, total |
|
34 hits |
|
35 number of objects, total |
|
36 last_on_page |
|
37 the result number of the last of object in the |
|
38 object_list (1-indexed) |
|
39 first_on_page |
|
40 the result number of the first object in the |
|
41 object_list (1-indexed) |
|
42 page_range: |
|
43 A list of the page numbers (1-indexed). |
|
44 """ |
|
45 if extra_context is None: extra_context = {} |
|
46 queryset = queryset._clone() |
|
47 if paginate_by: |
|
48 paginator = QuerySetPaginator(queryset, paginate_by, allow_empty_first_page=allow_empty) |
|
49 if not page: |
|
50 page = request.GET.get('page', 1) |
|
51 try: |
|
52 page_number = int(page) |
|
53 except ValueError: |
|
54 if page == 'last': |
|
55 page_number = paginator.num_pages |
|
56 else: |
|
57 # Page is not 'last', nor can it be converted to an int. |
|
58 raise Http404 |
|
59 try: |
|
60 page_obj = paginator.page(page_number) |
|
61 except InvalidPage: |
|
62 raise Http404 |
|
63 c = RequestContext(request, { |
|
64 '%s_list' % template_object_name: page_obj.object_list, |
|
65 'paginator': paginator, |
|
66 'page_obj': page_obj, |
|
67 |
|
68 # Legacy template context stuff. New templates should use page_obj |
|
69 # to access this instead. |
|
70 'is_paginated': page_obj.has_other_pages(), |
|
71 'results_per_page': paginator.per_page, |
|
72 'has_next': page_obj.has_next(), |
|
73 'has_previous': page_obj.has_previous(), |
|
74 'page': page_obj.number, |
|
75 'next': page_obj.next_page_number(), |
|
76 'previous': page_obj.previous_page_number(), |
|
77 'first_on_page': page_obj.start_index(), |
|
78 'last_on_page': page_obj.end_index(), |
|
79 'pages': paginator.num_pages, |
|
80 'hits': paginator.count, |
|
81 'page_range': paginator.page_range, |
|
82 }, context_processors) |
|
83 else: |
|
84 c = RequestContext(request, { |
|
85 '%s_list' % template_object_name: queryset, |
|
86 'paginator': None, |
|
87 'page_obj': None, |
|
88 'is_paginated': False, |
|
89 }, context_processors) |
|
90 if not allow_empty and len(queryset) == 0: |
|
91 raise Http404 |
|
92 for key, value in extra_context.items(): |
|
93 if callable(value): |
|
94 c[key] = value() |
|
95 else: |
|
96 c[key] = value |
|
97 if not template_name: |
|
98 model = queryset.model |
|
99 template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower()) |
|
100 t = template_loader.get_template(template_name) |
|
101 return HttpResponse(t.render(c), mimetype=mimetype) |
|
102 |
|
103 def object_detail(request, queryset, object_id=None, slug=None, |
|
104 slug_field='slug', template_name=None, template_name_field=None, |
|
105 template_loader=loader, extra_context=None, |
|
106 context_processors=None, template_object_name='object', |
|
107 mimetype=None): |
|
108 """ |
|
109 Generic detail of an object. |
|
110 |
|
111 Templates: ``<app_label>/<model_name>_detail.html`` |
|
112 Context: |
|
113 object |
|
114 the object |
|
115 """ |
|
116 if extra_context is None: extra_context = {} |
|
117 model = queryset.model |
|
118 if object_id: |
|
119 queryset = queryset.filter(pk=object_id) |
|
120 elif slug and slug_field: |
|
121 queryset = queryset.filter(**{slug_field: slug}) |
|
122 else: |
|
123 raise AttributeError, "Generic detail view must be called with either an object_id or a slug/slug_field." |
|
124 try: |
|
125 obj = queryset.get() |
|
126 except ObjectDoesNotExist: |
|
127 raise Http404, "No %s found matching the query" % (model._meta.verbose_name) |
|
128 if not template_name: |
|
129 template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower()) |
|
130 if template_name_field: |
|
131 template_name_list = [getattr(obj, template_name_field), template_name] |
|
132 t = template_loader.select_template(template_name_list) |
|
133 else: |
|
134 t = template_loader.get_template(template_name) |
|
135 c = RequestContext(request, { |
|
136 template_object_name: obj, |
|
137 }, context_processors) |
|
138 for key, value in extra_context.items(): |
|
139 if callable(value): |
|
140 c[key] = value() |
|
141 else: |
|
142 c[key] = value |
|
143 response = HttpResponse(t.render(c), mimetype=mimetype) |
|
144 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name)) |
|
145 return response |