0
# HTTP and Caching Utilities
1
2
Utility mixins for HTTP header manipulation, cache control, context enhancement, and URL handling. These mixins provide essential web development utilities for Django class-based views.
3
4
## Capabilities
5
6
### HTTP Header Management
7
8
Set custom HTTP headers on responses with flexible configuration.
9
10
```python { .api }
11
class HeaderMixin:
12
"""Add extra HTTP headers to response"""
13
headers = {}
14
15
def get_headers(self, request):
16
"""Override to customize headers dynamically"""
17
18
def dispatch(self, request, *args, **kwargs):
19
"""Override to customize header retrieval"""
20
```
21
22
Usage example:
23
24
```python
25
from django.views.generic import TemplateView
26
from braces.views import HeaderMixin
27
28
class CustomHeaderView(HeaderMixin, TemplateView):
29
template_name = 'page.html'
30
headers = {
31
'X-Custom-Header': 'MyValue',
32
'Access-Control-Allow-Origin': '*',
33
'X-Frame-Options': 'DENY'
34
}
35
36
def get_headers(self, request):
37
headers = super().get_headers(request)
38
39
# Dynamic headers based on request
40
if request.user.is_authenticated:
41
headers['X-User-ID'] = str(request.user.id)
42
43
# Conditional CORS
44
if request.META.get('HTTP_ORIGIN') in self.allowed_origins:
45
headers['Access-Control-Allow-Origin'] = request.META['HTTP_ORIGIN']
46
47
return headers
48
```
49
50
### Cache Control
51
52
Fine-grained cache control with support for all cache-control directives.
53
54
```python { .api }
55
class CacheControlMixin:
56
"""Mixin for setting Cache-Control options"""
57
cachecontrol_public = None
58
cachecontrol_private = None
59
cachecontrol_no_cache = None
60
cachecontrol_no_transform = None
61
cachecontrol_must_revalidate = None
62
cachecontrol_proxy_revalidate = None
63
cachecontrol_max_age = None
64
cachecontrol_s_maxage = None
65
66
@classmethod
67
def get_cachecontrol_options(cls):
68
"""Compile dictionary of selected cache options"""
69
70
@classmethod
71
def as_view(cls, *args, **kwargs):
72
"""Wrap view with appropriate cache controls"""
73
```
74
75
Usage example:
76
77
```python
78
from django.views.generic import ListView
79
from braces.views import CacheControlMixin
80
81
class CachedListView(CacheControlMixin, ListView):
82
model = MyModel
83
84
# Cache for 1 hour, allow public caching
85
cachecontrol_max_age = 3600
86
cachecontrol_public = True
87
cachecontrol_must_revalidate = True
88
89
class PrivateDataView(CacheControlMixin, ListView):
90
model = UserData
91
92
# Private data, no caching
93
cachecontrol_private = True
94
cachecontrol_no_cache = True
95
cachecontrol_no_transform = True
96
```
97
98
### Never Cache
99
100
Prevent all upstream caching with Django's never_cache decorator.
101
102
```python { .api }
103
class NeverCacheMixin:
104
"""Applies never_cache decorator to prevent HTTP-based caching"""
105
106
@classmethod
107
def as_view(cls, *args, **kwargs):
108
"""Wrap view with never_cache decorator"""
109
```
110
111
Usage example:
112
113
```python
114
from django.views.generic import FormView
115
from braces.views import NeverCacheMixin
116
117
class SensitiveFormView(NeverCacheMixin, FormView):
118
template_name = 'sensitive_form.html'
119
# This view will never be cached by browsers or proxies
120
```
121
122
### Context Enhancement
123
124
Add static context data and headlines to template context.
125
126
```python { .api }
127
class StaticContextMixin:
128
"""Set static context items via view attribute"""
129
static_context = None
130
131
def get_context_data(self, **kwargs):
132
"""Update context to include static content"""
133
134
def get_static_context(self):
135
"""Fetch static content from view"""
136
137
class SetHeadlineMixin:
138
"""Define headline context item as view attribute"""
139
headline = None
140
141
def get_context_data(self, **kwargs):
142
"""Add headline to context"""
143
144
def get_headline(self):
145
"""Fetch headline from instance"""
146
```
147
148
Usage example:
149
150
```python
151
from django.views.generic import ListView
152
from braces.views import StaticContextMixin, SetHeadlineMixin
153
154
class EnhancedListView(SetHeadlineMixin, StaticContextMixin, ListView):
155
model = MyModel
156
headline = "My Items List"
157
static_context = {
158
'page_title': 'Items',
159
'show_filters': True,
160
'max_items_per_page': 50,
161
'api_endpoints': {
162
'create': '/api/items/',
163
'bulk_delete': '/api/items/bulk-delete/'
164
}
165
}
166
167
def get_headline(self):
168
# Dynamic headlines
169
count = self.get_queryset().count()
170
return f"My Items List ({count} items)"
171
172
def get_static_context(self):
173
context = super().get_static_context()
174
175
# Dynamic static context
176
if self.request.user.is_staff:
177
context['admin_tools'] = True
178
context['show_advanced_filters'] = True
179
180
return context
181
```
182
183
### URL Canonicalization
184
185
Enforce canonical URLs with automatic redirects for slug-based detail views.
186
187
```python { .api }
188
class CanonicalSlugDetailMixin:
189
"""Enforce canonical slug in URL"""
190
191
def dispatch(self, request, *args, **kwargs):
192
"""Redirect to appropriate URL if necessary"""
193
194
def get_canonical_slug(self):
195
"""Provide method to return correct slug for object"""
196
```
197
198
Usage example:
199
200
```python
201
from django.views.generic import DetailView
202
from braces.views import CanonicalSlugDetailMixin
203
204
class ArticleDetailView(CanonicalSlugDetailMixin, DetailView):
205
model = Article
206
slug_field = 'slug'
207
slug_url_kwarg = 'slug'
208
209
def get_canonical_slug(self):
210
# Use the object's current slug as canonical
211
return self.get_object().slug
212
213
# If Article model has get_canonical_slug method:
214
class SmartArticleDetailView(CanonicalSlugDetailMixin, DetailView):
215
model = Article
216
# Will automatically use article.get_canonical_slug()
217
```
218
219
Model implementation:
220
221
```python
222
from django.db import models
223
from django.utils.text import slugify
224
225
class Article(models.Model):
226
title = models.CharField(max_length=200)
227
slug = models.SlugField(max_length=200)
228
229
def get_canonical_slug(self):
230
# Always generate slug from current title
231
return slugify(self.title)
232
233
def save(self, *args, **kwargs):
234
# Update slug on save
235
self.slug = self.get_canonical_slug()
236
super().save(*args, **kwargs)
237
```
238
239
### Single Method HTTP Handling
240
241
Route all HTTP methods to a single handler method.
242
243
```python { .api }
244
class AllVerbsMixin:
245
"""Call single method for all HTTP verbs"""
246
all_handler = 'all' # Method name to handle all requests
247
248
def dispatch(self, request, *args, **kwargs):
249
"""Call the all handler"""
250
```
251
252
Usage example:
253
254
```python
255
from django.views.generic import View
256
from braces.views import AllVerbsMixin
257
258
class UniversalAPIView(AllVerbsMixin, View):
259
all_handler = 'handle_request'
260
261
def handle_request(self, request, *args, **kwargs):
262
# Handle all HTTP methods (GET, POST, PUT, DELETE, etc.)
263
method = request.method
264
265
if method == 'GET':
266
return self.handle_get(request, *args, **kwargs)
267
elif method == 'POST':
268
return self.handle_post(request, *args, **kwargs)
269
# ... handle other methods
270
271
return HttpResponse(f"Method {method} handled", status=200)
272
```
273
274
## Common Usage Patterns
275
276
### API Response Headers
277
278
Standard headers for API endpoints:
279
280
```python
281
from django.views.generic import View
282
from braces.views import HeaderMixin, NeverCacheMixin, CsrfExemptMixin
283
284
class APIView(HeaderMixin, NeverCacheMixin, CsrfExemptMixin, View):
285
headers = {
286
'Content-Type': 'application/json',
287
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
288
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
289
'X-API-Version': '1.0'
290
}
291
292
def get_headers(self, request):
293
headers = super().get_headers(request)
294
295
# CORS headers based on request
296
origin = request.META.get('HTTP_ORIGIN')
297
if origin in settings.ALLOWED_ORIGINS:
298
headers['Access-Control-Allow-Origin'] = origin
299
headers['Access-Control-Allow-Credentials'] = 'true'
300
301
return headers
302
```
303
304
### Content Delivery Optimization
305
306
Optimize content delivery with appropriate caching:
307
308
```python
309
from django.views.generic import DetailView
310
from braces.views import CacheControlMixin, HeaderMixin
311
312
class OptimizedContentView(CacheControlMixin, HeaderMixin, DetailView):
313
model = Article
314
315
# Cache publicly for 1 hour
316
cachecontrol_public = True
317
cachecontrol_max_age = 3600
318
319
headers = {
320
'Vary': 'Accept-Encoding',
321
'X-Content-Type-Options': 'nosniff'
322
}
323
324
def get_cachecontrol_options(self):
325
options = super().get_cachecontrol_options()
326
327
# Dynamic cache control
328
obj = self.get_object()
329
if obj.is_breaking_news:
330
options['max_age'] = 300 # 5 minutes for breaking news
331
332
return options
333
```
334
335
### Enhanced Template Context
336
337
Rich context for complex templates:
338
339
```python
340
from django.views.generic import ListView
341
from braces.views import StaticContextMixin, SetHeadlineMixin
342
343
class DashboardView(SetHeadlineMixin, StaticContextMixin, ListView):
344
model = UserAction
345
template_name = 'dashboard.html'
346
347
def get_headline(self):
348
return f"Welcome back, {self.request.user.get_full_name()}"
349
350
def get_static_context(self):
351
return {
352
'navigation_items': self.get_navigation(),
353
'user_permissions': list(self.request.user.get_all_permissions()),
354
'feature_flags': settings.FEATURE_FLAGS,
355
'current_version': settings.APP_VERSION
356
}
357
358
def get_navigation(self):
359
# Build navigation based on user permissions
360
nav = []
361
if self.request.user.has_perm('app.view_reports'):
362
nav.append({'label': 'Reports', 'url': '/reports/'})
363
return nav
364
```