Django Formatting with Black & isort | Web Formatter Blog

Django Formatting with Black & isort
A comprehensive guide to setting up consistent Python code formatting in Django projects.
Introduction to Django Code Formatting
Consistent code formatting is essential for any Django project, especially when working in teams. Well-formatted code improves readability, reduces cognitive load, and eliminates unnecessary debates about code style. In the Python ecosystem, two tools have emerged as the gold standard for code formatting: Black and isort.
This guide will walk you through setting up and configuring these tools for your Django projects, ensuring your codebase remains clean, consistent, and maintainable.
Why Format Django Code?
Before diving into the tools, let's understand why automated formatting is particularly valuable for Django projects:
- Consistency across modules: Django projects often have many apps and modules. Consistent formatting makes navigation easier.
- Onboarding efficiency: New developers can focus on learning your business logic rather than adapting to custom style rules.
- Code review focus: Reviews can concentrate on functionality and architecture instead of style nitpicks.
- Django-specific patterns: Django has its own conventions that benefit from consistent formatting.
- Reduced merge conflicts: Consistent formatting reduces trivial conflicts during merges.
Black: The Uncompromising Python Formatter
Black calls itself "the uncompromising Python code formatter" because it gives you minimal configuration options. This is by design—Black aims to end debates about formatting by providing a single, consistent style.
Installing Black
You can install Black using pip:
# Install Black
pip install black
# Verify installation
black --version
For Django projects, it's recommended to add Black to your project's development dependencies:
# Using pip with requirements file
pip install black
echo "black==23.3.0" >> requirements-dev.txt
# Or using Poetry
poetry add black --dev
Using Black
To format a single file with Black:
black path/to/file.py
To format an entire Django project:
# Format all Python files in the current directory and subdirectories
black .
# Format specific Django apps
black myproject/ myapp/
# Check formatting without modifying files
black --check .
# Show diff of changes without applying them
black --diff .
Configuring Black
While Black is intentionally minimal in configuration options, you
can customize a few settings. Create a pyproject.toml
{" "}
file in your project root:
# pyproject.toml
[tool.black]
line-length = 88
target-version = ['py38']
include = '\\.pyi?$'
exclude = '''
/(
\\.git
| \\.hg
| \\.mypy_cache
| \\.tox
| \\.venv
| _build
| buck-out
| build
| dist
| migrations
)/
'''
Note that we've excluded migrations from formatting, which is a common practice in Django projects since migrations are often auto-generated.
isort: Sort Your Imports
While Black handles code formatting, isort specifically focuses on organizing and grouping your import statements. This is particularly useful in Django projects, which often have many imports from various modules.
Installing isort
Install isort using pip:
# Install isort
pip install isort
# Verify installation
isort --version
Add it to your development dependencies:
# Using pip with requirements file
pip install isort
echo "isort==5.12.0" >> requirements-dev.txt
# Or using Poetry
poetry add isort --dev
Using isort
To sort imports in a single file:
isort path/to/file.py
To sort imports across your Django project:
# Sort all Python files in the current directory and subdirectories
isort .
# Sort specific Django apps
isort myproject/ myapp/
# Check import sorting without modifying files
isort --check .
# Show diff of changes without applying them
isort --diff .
Configuring isort
isort offers more configuration options than Black. For Django
projects, you'll want to configure it to recognize Django-specific
imports. Add this to your pyproject.toml
:
# pyproject.toml
[tool.isort]
profile = "black"
line_length = 88
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
skip = ["migrations"]
known_django = "django"
known_first_party = ["myproject", "myapp"]
sections = ["FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
default_section = "THIRDPARTY"
The profile = "black"
setting ensures isort's output
is compatible with Black's formatting. We've also configured isort
to recognize Django imports and place them in their own section.
Integrating Black and isort
To ensure Black and isort work well together, you need to configure them with compatible settings. The key points are:
- Use the same line length for both tools
- Configure isort to use the "black" profile
- Run isort before Black in your workflow
Here's a complete pyproject.toml
configuration for
both tools:
# pyproject.toml
[tool.black]
line-length = 88
target-version = ['py38']
include = '\\.pyi?$'
exclude = '''
/(
\\.git
| \\.hg
| \\.mypy_cache
| \\.tox
| \\.venv
| _build
| buck-out
| build
| dist
| migrations
)/
'''
[tool.isort]
profile = "black"
line_length = 88
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
skip = ["migrations"]
known_django = "django"
known_first_party = ["myproject", "myapp"]
sections = ["FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
default_section = "THIRDPARTY"
To run both tools in sequence:
# Format imports first, then code
isort . && black .
# Check formatting without modifying files
isort --check . && black --check .
Django-Specific Formatting Considerations
Django projects have some unique characteristics that affect formatting:
- Migrations: As mentioned, it's best to exclude migrations from formatting.
- Models: Django models often have many fields and meta options. Black formats these consistently.
- URLs: URL patterns benefit from consistent formatting for readability.
- Settings: Django settings files can get long and complex; formatting helps maintain order.
Here's an example of how Black formats a Django model:
Editor Integration
Integrating Black and isort with your code editor provides real-time formatting as you work.
Visual Studio Code
For VS Code, install the Python extension and configure it to use Black and isort:
// settings.json
{
"python.formatting.provider": "black",
"python.formatting.blackPath": "black",
"python.formatting.blackArgs": [],
"editor.formatOnSave": true,
"python.linting.enabled": true,
"python.sortImports.path": "isort",
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}
PyCharm
For PyCharm, you can configure external tools:
- Go to Settings → Tools → External Tools
-
Add Black:
- Name: Black
- Program: path to black (e.g., $PyInterpreterDirectory$/black)
- Arguments: $FilePath$
- Working directory: $ProjectFileDir$
- Add isort similarly
- To run on save, install the File Watchers plugin and configure watchers for both tools
Vim / Neovim
For Vim or Neovim, you can use plugins like ALE or coc.nvim:
" Using ALE
Plug 'dense-analysis/ale'
let g:ale_fixers = {
\\ 'python': ['isort', 'black'],
\\}
let g:ale_fix_on_save = 1
" Or using coc.nvim
Plug 'neoclide/coc.nvim', {'branch': 'release'}
" Install coc-pyright extension
CI/CD Integration
Enforcing formatting in your CI/CD pipeline ensures all code meets your standards before merging.
GitHub Actions
Here's a GitHub Actions workflow for checking formatting:
# .github/workflows/code-quality.yml
name: Code Quality
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install black isort
- name: Check import sorting
run: isort --check --diff .
- name: Check formatting
run: black --check --diff .
GitLab CI
For GitLab CI, use a similar configuration:
# .gitlab-ci.yml
code_quality:
image: python:3.9
stage: lint
before_script:
- pip install black isort
script:
- isort --check --diff .
- black --check --diff .
Using pre-commit Hooks
Pre-commit hooks ensure code is formatted before it's committed. This is especially useful for teams:
# Install pre-commit
pip install pre-commit
pre-commit install
Create a .pre-commit-config.yaml
file:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
name: isort (python)
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
language_version: python3.9
Troubleshooting Common Issues
Here are solutions to common issues when using Black and isort with Django:
- Conflicts between Black and isort: Ensure you're using the "black" profile in isort configuration.
- Formatting migrations: Exclude migrations from formatting to avoid unnecessary changes.
- Line length issues: Use the same line length for both tools.
- Third-party code: Consider excluding vendor directories or third-party packages.
- Django templates: Black only formats Python files, not templates. Consider using a separate tool for templates.
Best Practices
Follow these best practices for formatting Django projects:
- Format early: Apply formatting from the beginning of your project.
- Format everything: Format all Python files except migrations and vendor code.
- Automate: Use editor integration, pre-commit hooks, and CI checks.
- Document: Include formatting instructions in your project README.
- Version pin: Pin Black and isort versions to avoid unexpected formatting changes.
- Batch format: When first adopting these tools, format the entire codebase in a single commit.
Conclusion
Consistent code formatting with Black and isort significantly improves the maintainability of Django projects. By automating formatting, you eliminate style debates, improve code readability, and let your team focus on what matters—building great Django applications.
Remember that the goal of formatting is not just aesthetic; it's about creating a consistent, predictable codebase that's easier to understand, maintain, and extend. With Black and isort properly configured, you'll achieve this goal with minimal effort.
Start implementing these tools in your Django projects today, and you'll quickly see the benefits of automated, consistent code formatting.