Skip to main content

Django Model Scanner

A static analysis tool for Django models using pylint and astroid. Scan Django model definitions and export them to structured YAML without importing or executing any Django code.

Why?

Existing Django model analysis tools require executing Django code (django.setup()), which:

  • ❌ Is slow (full application initialization)
  • ❌ Has side effects (signals, database connections)
  • ❌ Requires proper environment setup (settings, database config)
  • ❌ Cannot analyze broken or untrusted code safely

This tool uses static AST analysis with astroid to:

  • ✅ Scan models without code execution
  • ✅ Work without Django runtime or database
  • ✅ Handle all import styles and aliases
  • ✅ Support abstract inheritance
  • ✅ Export to structured YAML

Installation

pip install -e .

Important: Django must be installed for astroid type inference:

# Install with Django
pip install -e ".[examples]"

# Or install Django separately
pip install django>=3.2

Or with development dependencies:

pip install -e ".[dev]"

After installation, the django-model-scanner command will be available in your PATH.

Quick Start

CLI Usage (Recommended)

The simplest way to use the scanner:

# Scan a Django project or app
python -m django_model_scanner -p /path/to/project

# Or use the installed command
django-model-scanner -p /path/to/project

# Specify custom output location
python -m django_model_scanner -p ./myapp -o models.yaml

# Scan specific models file
django-model-scanner -p ./blog/models.py -o blog_models.yaml

This generates a YAML file (default: django_models.yaml) with all discovered models.

Usage with Pylint (Advanced)

For direct pylint integration:

# Scan specific models file
python -m pylint myapp/models.py \
  --load-plugins=django_model_scanner.checker \
  --disable=all

# Scan all Python files in directory (recursive)
python -m pylint myapp/*.py \
  --load-plugins=django_model_scanner.checker \
  --disable=all

# Scan entire project
python -m pylint . \
  --load-plugins=django_model_scanner.checker \
  --disable=all

This generates django_models.yaml with all discovered models.

CLI Reference

Command-line Options

python -m django_model_scanner [OPTIONS]
# or
django-model-scanner [OPTIONS]

Options:

  • -p, --project PATH (required): Path to Django project, app, or models.py file to scan
  • -o, --output FILE (optional): Output YAML file path (default: django_models.yaml)
  • --version: Show version and exit
  • -h, --help: Show help message and exit

Examples

# Basic usage with default output
django-model-scanner -p /path/to/project

# Custom output location
django-model-scanner -p ./src -o output/models.yaml

# Scan specific app
django-model-scanner -p ./blog -o blog_models.yaml

# Scan single models file
django-model-scanner -p ./myapp/models.py -o myapp.yaml

# Show help
django-model-scanner --help

# Show version
django-model-scanner --version

Advanced Usage (Pylint Integration)

For users who need direct pylint control:

Basic Scan

# Scan a specific models file
python -m pylint myapp/models.py --load-plugins=django_model_scanner.checker --disable=all

# Scan all .py files in a directory
python -m pylint myapp/*.py --load-plugins=django_model_scanner.checker --disable=all

# Scan entire project recursively
python -m pylint . --load-plugins=django_model_scanner.checker --disable=all

Custom Output Path

pylint myapp/ \
  --load-plugins=django_model_scanner.checker \
  --disable=all \
  --django-models-output=output/models.yaml

Verbose Mode

pylint myapp/ \
  --load-plugins=django_model_scanner.checker \
  --disable=all \
  --django-models-verbose=y

Output Format

Example YAML

blog.models.TimestampedModel:
  module: blog.models
  abstract: true
  bases: []
  fields:
    created_at:
      type: DateTimeField
      auto_now_add: true
    updated_at:
      type: DateTimeField
      auto_now: true

blog.models.Category:
  module: blog.models
  abstract: false
  bases: []
  table: blog_categories
  fields:
    id:
      type: AutoField
      primary_key: true
    name:
      type: CharField
      max_length: 100
    slug:
      type: SlugField
      unique: true

blog.models.Post:
  module: blog.models
  abstract: false
  bases:
    - blog.models.TimestampedModel
  table: blog_post
  fields:
    created_at:
      type: DateTimeField
      auto_now_add: true
    updated_at:
      type: DateTimeField
      auto_now: true
    title:
      type: CharField
      max_length: 200
    status:
      type: CharField
      max_length: 20
      choices:
        - [draft, Draft]
        - [published, Published]
        - [archived, Archived]
      default: draft
    author:
      type: ForeignKey
      on_delete: models.CASCADE
      related_name: posts
  relationships:
    author:
      type: ForeignKey
      to: auth.models.User
      on_delete: models.CASCADE
      related_name: posts
    category:
      type: ForeignKey
      to: blog.models.Category
      on_delete: models.SET_NULL
      related_name: posts

Schema Structure

Each model entry contains:

  • module: Python module path
  • abstract: Boolean indicating if model is abstract
  • bases: List of Django Model base classes (excluding django.db.models.Model)
  • table: Database table name (only for concrete models)
  • fields: Dictionary of field definitions
    • Field name → field properties (type, options)
    • Field choices are exported as structured lists
    • Defaults, booleans, and numbers are properly typed
  • relationships: Dictionary of relationship metadata (ForeignKey, ManyToMany, OneToOne)
    • Includes: to, on_delete, related_name, through, etc.

Features

✅ Model Detection

  • Detects Django models via inheritance from django.db.models.Model
  • Handles direct and indirect inheritance
  • Supports aliased imports (from django.db.models import Model as DjangoModel)
  • Works across files and modules

✅ Field Parsing

  • Extracts all Django field types (CharField, IntegerField, etc.)
  • Captures field options (max_length, null, blank, default, etc.)
  • Identifies primary keys
  • Handles various import styles

✅ Relationship Resolution

  • ForeignKey relationships
  • OneToOneField relationships
  • ManyToManyField relationships
  • Self-referential relationships ("self")
  • String model references ("app.Model", "Model")
  • Cascade behaviors (on_delete)
  • Related names and through models

✅ Abstract Inheritance

  • Identifies abstract models (Meta.abstract = True)
  • Merges fields from abstract parents into concrete children
  • Handles multi-level inheritance
  • Preserves field order per MRO

✅ YAML Export

  • Structured, machine-readable output
  • Normalized values (booleans, numbers, strings)
  • Preserves definition order
  • Separate fields and relationships sections

Example

See the examples/blog/models.py file for a complete example with:

  • Abstract base models
  • ForeignKey relationships
  • ManyToMany relationships
  • Self-referential relationships
  • OneToOne relationships
  • Custom table names

Run the scanner on the example:

# Scan the example models file
pylint examples/blog/models.py \
  --load-plugins=django_model_scanner.checker \
  --disable=all

# Or use the quickstart script
./quickstart.sh

How It Works

  1. Pylint Integration: Runs as a pylint checker, leveraging pylint's file traversal
  2. AST Analysis: Uses astroid to analyze Python AST without executing code
  3. Model Detection: Identifies Django models via inheritance checking
  4. Field Extraction: Parses field definitions and options from AST nodes
  5. Two-Pass Processing:
    • Pass 1: Collect all models
    • Pass 2: Merge abstract inheritance
  6. YAML Export: Normalizes values and exports to structured YAML

Architecture

┌─────────────────────┐
│  Pylint Framework   │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ DjangoModelChecker  │
│   (checker.py)      │
└──────────┬──────────┘
           │
    ┌──────┴──────┬──────────┐
    ▼             ▼          ▼
┌─────────┐  ┌─────────┐  ┌────────┐
│ast_utils│  │ model_  │  │export  │
│   .py   │  │parser.py│  │  .py   │
└─────────┘  └─────────┘  └────────┘

Use Cases

  • 📚 Documentation: Auto-generate model reference docs
  • 📊 ER Diagrams: Convert to diagram formats (Mermaid, GraphViz)
  • 🔍 Schema Analysis: Track model changes over time
  • ✅ Migration Validation: Compare models against migrations
  • 📈 Metrics: Calculate model complexity, field counts
  • 🔗 Relationship Mapping: Visualize model dependencies

Limitations

  • Dynamic Fields: Cannot detect programmatically generated fields
  • Proxy Models: Not supported in v0.1 (coming in future release)
  • Multi-table Inheritance: Not supported in v0.1
  • Custom Metaclasses: May not work with heavily customized model metaclasses
  • Standard App Structure: Assumes app.models module structure

Development

Run Tests

python tests/test_scanner.py

Or with pytest:

pytest tests/

Project Structure

django_model_scanner/
├── __init__.py       # Package initialization
├── ast_utils.py      # AST helper functions
├── model_parser.py   # Model parsing logic
├── export.py         # YAML export
└── checker.py        # Pylint checker

examples/
└── blog/
    └── models.py     # Example Django models

tests/
└── test_scanner.py   # Unit tests

Configuration

The checker supports these options:

  • --django-models-output=<path>: Output file path (default: django_models.yaml)
  • --django-models-verbose=<y/n>: Enable verbose output (default: n)

Contributing

Contributions welcome! Please:

  1. Follow the existing code style
  2. Add tests for new features
  3. Update documentation
  4. Keep changes focused and minimal

License

MIT License - see LICENSE file for details

Related Projects

Roadmap

  • Proxy model support
  • Multi-table inheritance
  • JSON export format
  • ER diagram generation
  • Migration validation
  • Schema diff tool
  • Custom field type plugins

Metadata

Release files for django-model-scanner 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-model-scanner 0.1.0
File Size Uploaded Provenance Actions
django_model_scanner-0.1.0.tar.gz 17.2 kB Without provenance Details for django_model_scanner-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-model-scanner 0.1.0
File Interpreter ABI Platform Actions
django_model_scanner-0.1.0-py3-none-any.whl Python 3 none any Details for django_model_scanner-0.1.0-py3-none-any.whl

Total release size: 35.4 kB

Release files / django_model_scanner-0.1.0.tar.gz

Download URL django_model_scanner-0.1.0.tar.gz
Size 17.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a601f27f634f28a6297364f38703c3491a6b8c6e8132fd83c843055d2ac815df
BLAKE2b-256 checksum
How to use checksums
fe94cb6abf60ccc81abfd43eb46ca903b856d96b465c6af6dfa8d6be7b97bc34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / django_model_scanner-0.1.0-py3-none-any.whl

Download URL django_model_scanner-0.1.0-py3-none-any.whl
Size 18.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
868592abf31a99bfbcb4d1892d3e262c99175ab9f993fbf1c50af9beb30144d1
BLAKE2b-256 checksum
How to use checksums
d57bb6970ab1be7a58ae53dc2fd6bd84cfedc019da46f6877c657fa83c953bbb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for django-model-scanner 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page