Skip to main content

🧾 django-annotate

Annotate Django model files with schema information (fields, indexes, and foreign keys), inspired by the annotaterb project for Rails.

✨ Features

  • Adds # == Schema Information blocks above each model class
  • Supports:
    • Field types
    • Indexes (including unique constraints)
    • Foreign key relationships
  • Works on monolithic or multi-file model setups
  • CLI support via Django's manage.py

🗄️ Database Support

Currently, django-annotate only supports PostgreSQL databases. This is because it uses PostgreSQL-specific system tables (pg_*) to introspect the database schema. Support for other databases (MySQL, SQLite) is planned for future releases.

Requirements

  • PostgreSQL database
  • Django project configured to use PostgreSQL as the database backend
  • Appropriate database permissions to query system tables
  • Standard Django ORM models (inheriting from django.db.models.Model)

If you're using a different database backend, you'll need to either:

  1. Switch to PostgreSQL
  2. Wait for support for your database to be added
  3. Contribute support for your database backend

📦 Installation

pip install django-annotate
# or if using Poetry:
poetry add django-annotate

⚙️ Setup

No configuration required — just install and run. If you want to run it via Django's CLI, ensure django_annotate is on your Python path (you don't need to add it to INSTALLED_APPS unless you want auto-discovery inside Django).

Then run:

python manage.py annotate_models

This will annotate models in all installed apps (excluding any apps listed in ignore_apps in your configuration).

To annotate a specific app:

python manage.py annotate_models --app=myapp

🔄 Auto-Annotation After Migrations

By default, model annotation runs automatically after every migration in development environments. This helps keep your model files up-to-date with your database schema.

Auto-annotation is disabled by default in production environments when DEBUG = False (typical in production).

To control auto-annotation behavior, you can configure the following settings in your .django_annotate.yml file:

# Auto-annotation settings
skip_on_migrate: false     # Set to true to disable auto-annotation after migrations
force: false               # Set to true to force annotation even if the file hasn't changed
frozen: false              # Set to true to prevent any automatic annotation

🧪 Example Output

# == Schema Information
#
# Table name: organizations
#
#  id         :bigint           not null, primary key
#  name       :varchar(255)     not null
#  created_at :timestamp        not null
#
# Indexes
#
#  organizations_pkey  (id)
#
# Foreign Keys
#
#  (none)
#

class Organization(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)


# == Schema Information
#
# Table name: users
#
#  id              :bigint           not null, primary key
#  email           :varchar(254)     not null
#  full_name       :varchar(255)     not null
#  organization_id :bigint           not null
#  created_at      :timestamp        not null
#
# Indexes
#
#  users_email_key            (email) UNIQUE
#  users_organization_id_idx  (organization_id)
#
# Foreign Keys
#
#  organization_id => organizations.id
#

class User(models.Model):
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
    email = models.EmailField(unique=True)
    full_name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)


# == Schema Information
#
# Table name: profiles
#
#  id      :bigint           not null, primary key
#  user_id :bigint           not null
#  bio     :text
#
# Indexes
#
#  profiles_user_id_key  (user_id) UNIQUE
#
# Foreign Keys
#
#  user_id => users.id
#

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)


# == Schema Information
#
# Table name: projects
#
#  id         :bigint           not null, primary key
#  name       :varchar(255)     not null
#  created_at :timestamp        not null
#
# Indexes
#
#  projects_pkey  (id)
#
# Foreign Keys
#
#  (none)
#

class Project(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    members = models.ManyToManyField(User, related_name="projects")

📜 License

MIT © 2025 Chris Davis

⚙️ Configuration

You can configure django-annotate by creating a .django_annotate.yml file in your project root. Here's a comprehensive list of all available configuration options:

# Position settings
position: before  # before or after the model class

# Schema information settings
show_indexes: true
show_foreign_keys: true
with_column_comments: true
include_version: false
timestamp: false

# Exclusion settings
ignore_models: []  # list of model names to ignore
ignore_apps: []    # list of app labels to ignore
ignore_columns: []

# Auto-annotation settings
skip_on_migrate: false
force: false
frozen: false

Quick Start

For most projects, you can start with a minimal configuration file. For example, to control auto-annotation behavior:

# Auto-annotation settings
skip_on_migrate: false  # Set to true to disable auto-annotation after migrations
force: false  # Set to true to force annotation even if the file hasn't changed
frozen: false  # Set to true to prevent any automatic annotation

All other settings will use sensible defaults. You can add more settings as needed.

Production Safety

By default, django-annotate will not run in production environments. This is enforced by:

  1. Not running when DEBUG = False (typical in production)
  2. Respecting the frozen setting in your configuration

To ensure safety in production, add this to your .django_annotate.yml:

# Auto-annotation settings
frozen: true  # Prevents any automatic annotation

The recommended workflow is:

  1. Run migrations and annotations locally
  2. Commit the annotated files to version control
  3. Deploy the committed files to production

Metadata

Release files for django-annotate 0.3.2

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-annotate 0.3.2
File Size Uploaded Provenance
django_annotate-0.3.2.tar.gz 12.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-annotate 0.3.2
File Interpreter ABI Platform
django_annotate-0.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 28.0 kB

Release files / django_annotate-0.3.2.tar.gz

Download URL django_annotate-0.3.2.tar.gz
Size 12.5 kB
Tags Source
SHA-256 checksum
How to use checksums
c7add1ec336278fdcbaea4227eb6bbb83652906799a98aec73a2caafdaed1552
BLAKE2b-256 checksum
How to use checksums
574fbba23b34ec468739c68cb2c87efa9b5d96ad852cdc24145cc1587608ed2a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.2 CPython/3.13.3 Darwin/24.4.0

Release files / django_annotate-0.3.2-py3-none-any.whl

Download URL django_annotate-0.3.2-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
781aec67a6d40185b8a520c3249b400305d3330456d312f3677f275568b18adf
BLAKE2b-256 checksum
How to use checksums
35f8a2bdbfdae5317465c16209ab73279d16137a3beee5703084194c1bd0be45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.2 CPython/3.13.3 Darwin/24.4.0

Security for django-annotate 0.3.2

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.

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