Reusable, generic mixins for Django class-based views
—
Mixins for handling AJAX requests and generating JSON responses in Django class-based views. These mixins enable seamless integration between frontend JavaScript and Django backends through AJAX endpoints and structured JSON APIs.
Basic JSON response functionality for API endpoints and AJAX responses.
class JSONResponseMixin:
"""Basic serialized JSON responses"""
content_type = None
json_dumps_kwargs = None
json_encoder_class = None
def get_content_type(self):
"""Get appropriate content type for response"""
def get_json_dumps_kwargs(self):
"""Get kwargs for custom JSON compilation"""
def get_json_encoder_class(self):
"""Get encoder class to use"""
def render_json_response(self, context_dict, status=200):
"""Limited serialization for shipping plain data"""
def render_json_object_response(self, objects, **kwargs):
"""Serialize objects using Django's builtin JSON serializer"""Usage example:
from django.views.generic import ListView
from braces.views import JSONResponseMixin
class APIDataView(JSONResponseMixin, ListView):
model = MyModel
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
data = {
'results': list(queryset.values('id', 'name', 'created')),
'count': queryset.count()
}
return self.render_json_response(data)
# Custom JSON encoder for datetime fields
json_encoder_class = DjangoJSONEncoder
json_dumps_kwargs = {'indent': 2}Separate method handlers for AJAX vs regular HTTP requests.
class AjaxResponseMixin:
"""Allows defining alternative methods for AJAX requests"""
def dispatch(self, request, *args, **kwargs):
"""Call appropriate handler method"""
def get_ajax(self, request, *args, **kwargs):
"""Handle GET request made with AJAX"""
def post_ajax(self, request, *args, **kwargs):
"""Handle POST request made with AJAX"""
def put_ajax(self, request, *args, **kwargs):
"""Handle PUT request made with AJAX"""
def delete_ajax(self, request, *args, **kwargs):
"""Handle DELETE request made with AJAX"""Usage example:
from django.views.generic import TemplateView
from braces.views import AjaxResponseMixin, JSONResponseMixin
class DualModeView(AjaxResponseMixin, JSONResponseMixin, TemplateView):
template_name = 'page.html'
def get(self, request, *args, **kwargs):
# Regular HTTP request - render template
return super().get(request, *args, **kwargs)
def get_ajax(self, request, *args, **kwargs):
# AJAX request - return JSON data
data = {'message': 'Hello from AJAX!'}
return self.render_json_response(data)
def post_ajax(self, request, *args, **kwargs):
# Handle AJAX form submissions
form_data = request.POST
# Process form...
return self.render_json_response({'status': 'success'})Parse and validate JSON request bodies with error handling.
class JsonRequestResponseMixin(JSONResponseMixin):
"""Attempt to parse request body as JSON"""
require_json = False
error_response_dict = {'errors': ['Improperly formatted request']}
def render_bad_request_response(self, error_dict=None):
"""Generate errors for bad content"""
def get_request_json(self):
"""Get JSON included in the body"""
def dispatch(self, request, *args, **kwargs):
"""Trigger appropriate method"""class JSONRequestResponseMixin(JsonRequestResponseMixin):
"""Convenience alias for JsonRequestResponseMixin"""Usage example:
from django.views.generic import View
from braces.views import JsonRequestResponseMixin, CsrfExemptMixin
class APIEndpoint(CsrfExemptMixin, JsonRequestResponseMixin, View):
require_json = True # Return 400 for non-JSON requests
def post(self, request, *args, **kwargs):
# self.request_json contains parsed JSON data
if self.request_json is None:
return self.render_bad_request_response()
# Process JSON data
name = self.request_json.get('name')
email = self.request_json.get('email')
# Validate and save...
result = {'id': 123, 'status': 'created'}
return self.render_json_response(result, status=201)
def put(self, request, *args, **kwargs):
# Update existing record
record_id = kwargs.get('pk')
data = self.request_json
# Update logic...
return self.render_json_response({'status': 'updated'})Combine mixins for full REST API functionality:
from django.views.generic import View
from braces.views import CsrfExemptMixin, JsonRequestResponseMixin, AjaxResponseMixin
class RESTAPIView(CsrfExemptMixin, JsonRequestResponseMixin, AjaxResponseMixin, View):
require_json = True
def get(self, request, *args, **kwargs):
# Return JSON list or detail
return self.render_json_response({'data': []})
def post(self, request, *args, **kwargs):
# Create new resource from JSON
return self.render_json_response({'created': True}, status=201)
def put(self, request, *args, **kwargs):
# Update resource from JSON
return self.render_json_response({'updated': True})
def delete(self, request, *args, **kwargs):
# Delete resource
return self.render_json_response({'deleted': True}, status=204)Handle both regular page loads and AJAX requests:
from django.views.generic import CreateView
from braces.views import AjaxResponseMixin, JSONResponseMixin
class ProgressiveFormView(AjaxResponseMixin, JSONResponseMixin, CreateView):
model = MyModel
template_name = 'form.html'
def form_valid(self, form):
# Save the object
response = super().form_valid(form)
return response
def form_valid_ajax(self, form):
# AJAX version - return JSON instead of redirect
self.object = form.save()
return self.render_json_response({
'success': True,
'id': self.object.pk,
'url': self.object.get_absolute_url()
})
def form_invalid_ajax(self, form):
# Return form errors as JSON
return self.render_json_response({
'success': False,
'errors': form.errors
}, status=400)Handle complex data types with custom encoders:
import json
from decimal import Decimal
from datetime import datetime
from django.core.serializers.json import DjangoJSONEncoder
from braces.views import JSONResponseMixin
class CustomJSONEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return float(obj)
return super().default(obj)
class CustomJSONView(JSONResponseMixin, View):
json_encoder_class = CustomJSONEncoder
json_dumps_kwargs = {'indent': 2, 'sort_keys': True}
def get(self, request):
data = {
'timestamp': datetime.now(),
'price': Decimal('29.99'),
'items': ['item1', 'item2']
}
return self.render_json_response(data)Install with Tessl CLI
npx tessl i tessl/pypi-django-braces