Professional Django utilities for modern web development
π Documentation | π Quick Start | π‘ Examples | π€ Contributing | π Changelog
Transform your Django development with a comprehensive suite of production-ready utilities, mixins, and tools. Designed by Django experts for Django developers who demand quality, performance, and maintainability.
π― Production Ready - Battle-tested in real-world applications
β‘ Performance Focused - Optimized for speed and efficiency
π§ Developer Friendly - Intuitive APIs with comprehensive documentation
π‘οΈ Type Safe - Full type hints support with mypy compatibility
π Modern Django - Supports Django 4.2+ with async capabilities
π± Responsive Design - Admin tools that work beautifully on all devices
# Using pip
pip install django-sage-tools
# Using Poetry (recommended)
poetry add django-sage-tools
# Using pipenv
pipenv install django-sage-tools
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
# ... other apps
'sage_tools', # Add this line
]
# Optional: Add configuration
SAGE_TOOLS = {
'AUTO_SLUGIFY_ENABLED': True,
'CLEANUP_DELETE_FILES': True,
}
# models.py
from django.db import models
from sage_tools.mixins.models.base import TimeStampMixin, UUIDBaseModel
class Article(TimeStampMixin, UUIDBaseModel):
title = models.CharField(max_length=200)
content = models.TextField()
def __str__(self):
return self.title
# views.py
from django.views.generic import ListView
from sage_tools.mixins.views.access import LoginRequiredMixin
from sage_tools.mixins.views.cache import CacheControlMixin
class ArticleListView(LoginRequiredMixin, CacheControlMixin, ListView):
model = Article
template_name = 'articles/list.html'
cache_timeout = 300 # 5 minutes
That's it! π Your model now has UUID primary keys, automatic timestamps, and your view requires authentication with smart caching.
π View Mixins - Supercharge your class-based views
LoginRequiredMixin
- Ensure user authenticationAnonymousRequiredMixin
- Restrict authenticated usersAccessMixin
- Advanced permission handling
CacheControlMixin
- Smart HTTP cachingNeverCacheMixin
- Prevent caching when neededHTTPHeaderMixin
- Custom HTTP headers
FormMessagesMixin
- Automatic success/error messagesLocaleMixin
- Multi-language support
from sage_tools.mixins.views import (
LoginRequiredMixin, CacheControlMixin, FormMessagesMixin
)
class ProductCreateView(LoginRequiredMixin, FormMessagesMixin, CreateView):
model = Product
template_name = 'products/create.html'
success_message = "Product created successfully! π"
error_message = "Please correct the errors below."
ποΈ Model Mixins - Enhance your Django models
TimeStampMixin
- Automatic created/modified timestampsUUIDBaseModel
- UUID primary keys for better securityBaseTitleSlugMixin
- SEO-friendly URLs with auto-generated slugs
AddressMixin
- Complete address handlingRatingMixin
- Star rating systemCommentMixin
- User comments and reviews
from sage_tools.mixins.models import TimeStampMixin, UUIDBaseModel, RatingMixin
class Restaurant(TimeStampMixin, UUIDBaseModel, RatingMixin):
name = models.CharField(max_length=100)
cuisine = models.CharField(max_length=50)
# Automatically includes: id (UUID), created_at, modified_at, rating fields
β‘ Validators - Bulletproof data validation
FileSizeValidator
- Control upload sizesFileTypeValidator
- Restrict file types
NameValidator
- Validate person namesHalfPointIncrementValidator
- Rating validation (0.5, 1.0, 1.5...)NumeralValidator
- Number format validation
from sage_tools.validators import FileSizeValidator, NameValidator
class UserProfile(models.Model):
name = models.CharField(
max_length=100,
validators=[NameValidator()]
)
avatar = models.ImageField(
upload_to='avatars/',
validators=[FileSizeValidator(max_size=5*1024*1024)] # 5MB limit
)
π§ Admin Tools - Professional Django admin experience
ReadOnlyAdmin
- View-only admin interfacesLimitOneInstanceAdminMixin
- Singleton pattern enforcementAdminPrioritizeApp
- Customize admin app ordering
from django.contrib import admin
from sage_tools.mixins.admins import LimitOneInstanceAdminMixin
@admin.register(SiteConfiguration)
class SiteConfigAdmin(LimitOneInstanceAdminMixin, admin.ModelAdmin):
# Only allows one site configuration instance
pass
π Security & Encryption - Keep your data safe
FernetEncryptor
- Symmetric encryption for sensitive dataSessionEncryptor
- Secure session data handlingDummyEncryptor
- Testing and development placeholder
- CSRF handling utilities
- Secure file upload handling
- Session security enhancements
from sage_tools.encryptors import FernetEncryptor
# settings.py
FERNET_SECRET_KEY = "your-secret-key-here"
# Usage
encryptor = FernetEncryptor()
encrypted_data = encryptor.encrypt("sensitive information")
decrypted_data = encryptor.decrypt(encrypted_data)
from django.db import models
from sage_tools.mixins.models import (
TimeStampMixin, UUIDBaseModel, RatingMixin
)
from sage_tools.validators import FileSizeValidator
class Product(TimeStampMixin, UUIDBaseModel, RatingMixin):
name = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
image = models.ImageField(
upload_to='products/',
validators=[FileSizeValidator(max_size=2*1024*1024)] # 2MB
)
is_active = models.BooleanField(default=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return f"{self.name} - ${self.price}"
from django.views.generic import TemplateView
from sage_tools.mixins.views import (
LoginRequiredMixin, CacheControlMixin, AccessMixin
)
class AdminDashboardView(LoginRequiredMixin, AccessMixin, CacheControlMixin, TemplateView):
template_name = 'admin/dashboard.html'
cache_timeout = 600 # 10 minutes
permission_required = 'auth.view_user'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'total_users': User.objects.count(),
'active_sessions': Session.objects.filter(expire_date__gte=timezone.now()).count(),
'recent_orders': Order.objects.filter(created_at__gte=timezone.now() - timedelta(days=7)),
})
return context
from django.views.generic import CreateView
from sage_tools.mixins.views import FormMessagesMixin
from sage_tools.mixins.forms import UserFormMixin
class ContactFormView(FormMessagesMixin, UserFormMixin, CreateView):
model = Contact
fields = ['name', 'email', 'subject', 'message']
template_name = 'contact/form.html'
success_url = '/contact/thank-you/'
# Auto-injected messages
success_message = "Thank you! We'll get back to you soon. π§"
error_message = "Please check the form for errors."
def form_valid(self, form):
# Auto-assigns current user if available
return super().form_valid(form)
# settings.py
SAGE_TOOLS = {
# Encryption
'FERNET_SECRET_KEY': env('FERNET_SECRET_KEY'),
# File handling
'CLEANUP_DELETE_FILES': True,
'MAX_UPLOAD_SIZE': 10 * 1024 * 1024, # 10MB
# Slugs
'AUTO_SLUGIFY_ENABLED': True,
'SLUG_SEPARATOR': '-',
# Caching
'DEFAULT_CACHE_TIMEOUT': 300, # 5 minutes
# Admin
'ADMIN_REORDER_APPS': True,
}
# .env
FERNET_SECRET_KEY=your-32-character-base64-key-here
DJANGO_DEBUG=False
DJANGO_SECRET_KEY=your-django-secret-key
# Run tests
python -m pytest
# With coverage
python -m pytest --cov=sage_tools
# Specific test module
python -m pytest tests/test_mixins.py -v
# test_integration.py
from django.test import TestCase
from sage_tools.mixins.models import TimeStampMixin, UUIDBaseModel
class TestSageToolsIntegration(TestCase):
def test_model_mixins(self):
# Test your models with Sage Tools mixins
article = Article.objects.create(title="Test", content="Content")
# UUID primary key
self.assertIsInstance(article.id, UUID)
# Automatic timestamps
self.assertIsNotNone(article.created_at)
self.assertIsNotNone(article.modified_at)
# Use select_related with TimeStampMixin models
articles = Article.objects.select_related('author').prefetch_related('tags')
# Leverage UUID indexes
class Meta:
indexes = [
models.Index(fields=['created_at']),
models.Index(fields=['id', 'created_at']),
]
# Smart cache invalidation
class ArticleListView(CacheControlMixin, ListView):
cache_timeout = 600 # 10 minutes
cache_key_prefix = 'articles'
def get_cache_key(self):
return f"{self.cache_key_prefix}:{self.request.user.id}"
- π Use UUIDs for public-facing model IDs
- π« Validate uploads with FileSizeValidator
- π Encrypt sensitive data with FernetEncryptor
- β‘ Rate limit admin actions with custom mixins
- π‘οΈ Sanitize user input with built-in validators
# Old way
from sage_tools.utils import some_function
# New way (v0.3.x)
from sage_tools import some_function
- Renamed
BaseModel
toUUIDBaseModel
for clarity CacheMixin
split intoCacheControlMixin
andNeverCacheMixin
- Updated minimum Django version to 4.2
Component | Version Support |
---|---|
Python | 3.8, 3.9, 3.10, 3.11, 3.12 |
Django | 4.2, 5.0, 5.1, 5.2 |
Database | PostgreSQL, MySQL, SQLite |
Cache | Redis, Memcached, Database |
# Clone repository
git clone https://github.com/sageteamorg/django-sage-tools.git
cd django-sage-tools
# Install dependencies
poetry install
# Run quality checks
make format lint test
# Run pre-commit hooks
make pre-commit
make help # Show all available commands
make install # Install dependencies
make test # Run tests
make format # Format code
make lint # Run linting
make build # Build package
make publish-test # Publish to Test PyPI
make publish # Publish to PyPI
Common Issues
# β Wrong
from sage_tools.mixins import TimeStampMixin
# β
Correct
from sage_tools.mixins.models import TimeStampMixin
# or
from sage_tools import TimeStampMixin
# If you get UUID field errors, ensure:
# 1. Migrations are up to date
python manage.py makemigrations
python manage.py migrate
# 2. Database supports UUIDs (PostgreSQL recommended)
# Ensure cache backend is configured
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
"Django Sage Tools transformed our development workflow. The mixins are incredibly powerful and the documentation is top-notch!"
β Sarah Chen, Lead Developer at TechCorp
"We reduced our boilerplate code by 60% using Sage Tools. The UUID and timestamp mixins alone saved us weeks of development."
β Marcus Rodriguez, CTO at StartupXYZ
- π Full Documentation
- π₯ Video Tutorials
- π‘ Best Practices Guide
- π― Migration Guide
We β€οΈ contributions! Here's how you can help:
- π΄ Fork the repository
- π Star the project
- π Report bugs via issues
- π‘ Suggest features via discussions
- π Improve documentation
- Clone:
git clone https://github.com/sageteamorg/django-sage-tools.git
- Setup:
make dev-setup
- Code: Follow our style guide
- Test:
make test
- Submit: Create a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- π Django Team - For the amazing framework
- ποΈ Python Community - For the incredible ecosystem
- π¨ Contributors - For making this project awesome
- β Coffee - For fueling late-night coding sessions
- π Bug Reports: GitHub Issues
- π¬ Discussions: GitHub Discussions
- π§ Email: [email protected]
- π¦ Twitter: @sageteamorg
Made with β€οΈ by the Sage Team