Skip to main content
Course/Module 6/Topic 3 of 5Intermediate

Code Quality & Linting

Learn tools and practices for maintaining high code quality in Django projects.

65 minBy Priygop TeamLast updated: Feb 2026

Code Quality Tools

Maintaining high code quality is essential for long-term project success. Various tools help enforce coding standards and identify potential issues.

Linting & Code Analysis

Example
# Code Quality Tools Setup

# requirements-dev.txt (Development dependencies)
flake8==6.0.0
black==23.3.0
isort==5.12.0
pylint==2.17.4
mypy==1.3.0
bandit==1.7.5
pre-commit==3.3.2

# .flake8 configuration
[flake8]
max-line-length = 88
extend-ignore = E203, W503
exclude = 
    .git,
    __pycache__,
    .venv,
    venv,
    env,
    migrations,
    staticfiles,
    media

# Black configuration (pyproject.toml)
[tool.black]
line-length = 88
target-version = ['py39']
include = '\.pyi?$'
extend-exclude = '''
/(
  # directories
  \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | _build
  | buck-out
  | build
  | dist
)/
'''

# isort configuration (pyproject.toml)
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
known_django = "django"
known_first_party = "myapp"
sections = ["FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]

# Pylint configuration (.pylintrc)
[MASTER]
disable=
    C0114, # missing-module-docstring
    C0115, # missing-class-docstring
    C0116, # missing-function-docstring

[FORMAT]
max-line-length=88

[MESSAGES CONTROL]
disable=
    C0103, # invalid-name
    C0301, # line-too-long
    R0903, # too-few-public-methods
    R0913, # too-many-arguments

# MyPy configuration (pyproject.toml)
[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true

[[tool.mypy.overrides]]
module = [
    "django.*",
    "django_extensions.*",
]
ignore_missing_imports = true

# Pre-commit hooks (.pre-commit-config.yaml)
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
      - id: check-merge-conflict
  
  - repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
      - id: black
        language_version: python3
  
  - repo: https://github.com/pycqa/isort
    rev: 5.12.0
    hooks:
      - id: isort
  
  - repo: https://github.com/pycqa/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
  
  - repo: https://github.com/pycqa/bandit
    rev: 1.7.5
    hooks:
      - id: bandit
        args: [-r, ., -f, json, -o, bandit-report.json]

# Custom Django management command for code quality
# management/commands/check_code_quality.py
from django.core.management.base import BaseCommand
import subprocess
import sys

class Command(BaseCommand):
    help = 'Check code quality using various tools'
    
    def add_arguments(self, parser):
        parser.add_argument(
            '--fix',
            action='store_true',
            help='Automatically fix formatting issues'
        )
    
    def handle(self, *args, **options):
        tools = [
            ('Black', ['black', '--check', '.']),
            ('isort', ['isort', '--check-only', '.']),
            ('Flake8', ['flake8', '.']),
            ('Pylint', ['pylint', 'myapp/']),
            ('MyPy', ['mypy', '.']),
            ('Bandit', ['bandit', '-r', '.']),
        ]
        
        failed_tools = []
        
        for tool_name, command in tools:
            self.stdout.write(f'Running {tool_name}...')
            
            try:
                result = subprocess.run(
                    command,
                    capture_output=True,
                    text=True
                )
                
                if result.returncode == 0:
                    self.stdout.write(
                        self.style.SUCCESS(f'{tool_name}: PASSED')
                    )
                else:
                    self.stdout.write(
                        self.style.ERROR(f'{tool_name}: FAILED')
                    )
                    self.stdout.write(result.stdout)
                    self.stdout.write(result.stderr)
                    failed_tools.append(tool_name)
                    
            except FileNotFoundError:
                self.stdout.write(
                    self.style.WARNING(f'{tool_name}: Not installed')
                )
        
        if failed_tools:
            self.stdout.write(
                self.style.ERROR(
                    f'Code quality checks failed for: {", ".join(failed_tools)}'
                )
            )
            sys.exit(1)
        else:
            self.stdout.write(
                self.style.SUCCESS('All code quality checks passed!')
            )

# Usage: python manage.py check_code_quality

# GitHub Actions workflow for code quality
# .github/workflows/code-quality.yml
name: Code Quality

on: [push, pull_request]

jobs:
  quality:
    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 -r requirements-dev.txt
      
      - name: Run Black
        run: black --check .
      
      - name: Run isort
        run: isort --check-only .
      
      - name: Run Flake8
        run: flake8 .
      
      - name: Run Pylint
        run: pylint myapp/
      
      - name: Run MyPy
        run: mypy .
      
      - name: Run Bandit
        run: bandit -r . -f json -o bandit-report.json

# IDE Configuration (VS Code)
# .vscode/settings.json
{
    "python.linting.enabled": true,
    "python.linting.flake8Enabled": true,
    "python.linting.pylintEnabled": true,
    "python.linting.mypyEnabled": true,
    "python.formatting.provider": "black",
    "python.sortImports.args": ["--profile", "black"],
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.organizeImports": true
    },
    "python.linting.flake8Args": ["--max-line-length=88"],
    "python.linting.pylintArgs": ["--max-line-length=88"]
}

Additional Resources

Recommended Reading

  • Django Deployment Checklist
  • Django Performance Optimization Guide
  • Django Monitoring Best Practices

Online Resources

  • Heroku Django Deployment Tutorial
  • DigitalOcean Django Guide
  • AWS Elastic Beanstalk Documentation
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep