or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

access-control.mdajax-json.mdform-processing.mdhttp-utilities.mdindex.mdquery-optimization.md

http-utilities.mddocs/

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

```