Reusable, generic mixins for Django class-based views
—
Mixins for enhanced form processing, validation messaging, CSRF handling, and context injection. These mixins solve common form-related challenges in Django class-based views and provide consistent user feedback patterns.
Exempt views from CSRF protection for API endpoints and special cases.
class CsrfExemptMixin:
"""Exempts the view from CSRF requirements"""
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
"""Dispatch with CSRF exemption applied"""Usage example:
from django.views.generic import CreateView
from braces.views import CsrfExemptMixin, JsonRequestResponseMixin
class APICreateView(CsrfExemptMixin, JsonRequestResponseMixin, CreateView):
model = MyModel
def post(self, request, *args, **kwargs):
# Process JSON data without CSRF token
data = self.request_json
# Create object...
return self.render_json_response({'status': 'created'})Note: CsrfExemptMixin should be the leftmost mixin in inheritance chain.
Automatically pass the current user to form initialization.
class UserFormKwargsMixin:
"""Automatically include request.user in form kwargs"""
def get_form_kwargs(self):
"""Update form kwargs with current user"""Usage example:
from django.views.generic import CreateView
from braces.views import UserFormKwargsMixin
class UserAwareCreateView(UserFormKwargsMixin, CreateView):
model = MyModel
form_class = MyModelForm
# Form will receive user in __init__Form implementation:
from django import forms
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None) # Extract user from kwargs
super().__init__(*args, **kwargs)
# Use self.user for field customization
if self.user and not self.user.is_staff:
del self.fields['admin_notes']
class Meta:
model = MyModel
fields = '__all__'For direct use in form classes (imported from braces.forms):
class UserKwargModelFormMixin:
"""Form mixin for popping user out of kwargs and attaching to instance"""
user = None
def __init__(self, *args, **kwargs):
"""Remove user from kwargs and assign to self.user"""Usage example:
from django import forms
from braces.forms import UserKwargModelFormMixin
class MyModelForm(UserKwargModelFormMixin, forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # Automatically extracts user
# Now self.user is available for customization
if self.user and not self.user.is_staff:
del self.fields['admin_notes']
class Meta:
model = MyModel
fields = '__all__'
# Usage in view
class MyCreateView(UserFormKwargsMixin, CreateView):
model = MyModel
form_class = MyModelForm # Form will receive user automaticallyAutomatic success URL generation from named URL patterns.
class SuccessURLRedirectListMixin:
"""Automatically reverse success_list_url as success_url"""
success_list_url = None
def get_success_url(self):
"""Return reversed success url"""Usage example:
from django.views.generic import CreateView
from braces.views import SuccessURLRedirectListMixin
class CreateItemView(SuccessURLRedirectListMixin, CreateView):
model = Item
success_list_url = 'item:list' # URL name to redirect to after successConsistent success and error messaging for form processing.
class MessageMixin:
"""Add messages attribute for Django's messages framework"""
# Provides self.messages with methods: add_message, debug, info, success, warning, error
def __init__(self, *args, **kwargs):
"""Initialize with class name reference"""
class FormValidMessageMixin(MessageMixin):
"""Set message when form passes validation"""
form_valid_message = None
def get_form_valid_message(self):
"""Validate that form_valid_message is set correctly"""
def form_valid(self, form):
"""Set form valid message for standard validation"""
def delete(self, *args, **kwargs):
"""Set form valid message for delete operations"""
class FormInvalidMessageMixin(MessageMixin):
"""Set message when form fails validation"""
form_invalid_message = None
def get_form_invalid_message(self):
"""Validate that form_invalid_message is set correctly"""
def form_invalid(self, form):
"""Set form invalid message for validation failures"""
class FormMessagesMixin(FormValidMessageMixin, FormInvalidMessageMixin):
"""Combines valid and invalid message mixins"""Usage examples:
from django.views.generic import CreateView, UpdateView
from braces.views import FormValidMessageMixin, FormInvalidMessageMixin, FormMessagesMixin
# Success messages only
class CreateWithSuccessView(FormValidMessageMixin, CreateView):
model = MyModel
form_valid_message = "Item created successfully!"
# Error messages only
class UpdateWithErrorView(FormInvalidMessageMixin, UpdateView):
model = MyModel
form_invalid_message = "Please correct the errors below."
# Both success and error messages
class FullMessageView(FormMessagesMixin, CreateView):
model = MyModel
form_valid_message = "Item created successfully!"
form_invalid_message = "Please fix the form errors."Direct access to Django's messages framework:
from django.views.generic import FormView
from braces.views import MessageMixin
class CustomMessageView(MessageMixin, FormView):
def form_valid(self, form):
# Direct message usage
self.messages.success("Form submitted successfully!")
self.messages.info("Processing will begin shortly.")
# Conditional messaging
if form.cleaned_data.get('notify_admin'):
self.messages.warning("Admin will be notified.")
return super().form_valid(form)
def form_invalid(self, form):
self.messages.error("There were errors in your submission.")
# Add specific field errors
for field, errors in form.errors.items():
for error in errors:
self.messages.error(f"{field}: {error}")
return super().form_invalid(form)Combine multiple mixins for comprehensive form handling:
from django.views.generic import CreateView
from braces.views import (
LoginRequiredMixin, UserFormKwargsMixin,
FormMessagesMixin, SuccessURLRedirectListMixin
)
class CompleteCreateView(
LoginRequiredMixin,
UserFormKwargsMixin,
FormMessagesMixin,
SuccessURLRedirectListMixin,
CreateView
):
model = MyModel
form_class = MyModelForm
login_url = '/login/'
form_valid_message = "Item created successfully!"
form_invalid_message = "Please correct the errors below."
success_list_url = 'myapp:item_list'Combine with JSON mixins for API endpoints:
from django.views.generic import CreateView
from braces.views import CsrfExemptMixin, JsonRequestResponseMixin, UserFormKwargsMixin
class APIFormView(CsrfExemptMixin, JsonRequestResponseMixin, UserFormKwargsMixin, CreateView):
model = MyModel
form_class = MyModelForm
def form_valid(self, form):
# Save object
self.object = form.save()
# Return JSON response
return self.render_json_response({
'success': True,
'id': self.object.pk,
'message': 'Created successfully'
}, status=201)
def form_invalid(self, form):
# Return form errors as JSON
return self.render_json_response({
'success': False,
'errors': form.errors
}, status=400)Dynamic form behavior based on user or context:
from django.views.generic import UpdateView
from braces.views import UserFormKwargsMixin, FormMessagesMixin
class ConditionalUpdateView(UserFormKwargsMixin, FormMessagesMixin, UpdateView):
model = MyModel
def get_form_valid_message(self):
if self.request.user.is_staff:
return "Administrative update completed."
return "Your changes have been saved."
def get_form_invalid_message(self):
return "Please correct the errors and try again."
def form_valid(self, form):
# Custom validation based on user
if not self.request.user.is_staff:
# Remove admin-only changes
form.instance.admin_approved = False
return super().form_valid(form)Install with Tessl CLI
npx tessl i tessl/pypi-django-braces