Skip to main content

Configuration Auditing and Introspection

To audit your project's configuration or bootstrap models from an existing database, this project provides diagnostic management commands: diffsettings for configuration analysis and inspectdb for schema introspection.

Auditing Project Settings

Use the diffsettings command to identify how your current configuration deviates from Django's defaults or from a base settings module. This is the primary tool for debugging environment-specific overrides.

# Display settings that differ from Django's defaults (hash mode)
python manage.py diffsettings

# Display differences in a unified diff format
python manage.py diffsettings --output=unified

# Compare against a specific settings module
python manage.py diffsettings --default=myproject.base_settings

Output Formats

The diffsettings.Command supports two output modes via the --output argument:

  • hash (default): Displays changed settings. Settings that exist in your project but not in the defaults are followed by ###.
  • unified: Uses a standard diff format. Default values are prefixed with - and your project's values are prefixed with +.

To see every setting including those that match the defaults, use the --all flag:

python manage.py diffsettings --all

How Settings are Filtered

The command uses module_to_dict in django/core/management/commands/diffsettings.py to process the settings module. It only considers settings that meet two criteria:

  1. The key is in all UPPERCASE.
  2. The key does not start with an underscore (_).

Values are compared using their repr() string representation.

Introspecting Existing Databases

To generate Django models from a legacy or external database, use the inspectdb command. It examines the database schema and outputs Python model code to stdout.

# Introspect the entire default database and save to a file
python manage.py inspectdb > models.py

# Introspect specific tables only
python manage.py inspectdb table_name_1 table_name_2

# Introspect a specific database alias defined in your settings
python manage.py inspectdb --database=external_db

Handling Views and Partitions

By default, inspectdb only processes standard tables. Use flags to include other database entities:

# Include database views and partition tables
python manage.py inspectdb --include-views --include-partitions

Post-Introspection Cleanup

The inspectdb.Command generates code that requires manual review before production use. The generated output includes comments reminding you to:

  1. Review managed = False: Generated models include managed = False in the Meta class by default. This prevents Django's migration system from modifying the existing table. Remove this if you want Django to manage the table lifecycle.
  2. Define Primary Keys: Django requires a single-column primary key. If your table has a composite primary key, inspectdb will generate models.CompositePrimaryKey, but you must verify it matches your requirements.
  3. Configure on_delete: Foreign key relationships default to models.DO_NOTHING. You must manually update these to CASCADE, SET_NULL, or other behaviors as needed.
  4. Verify Field Types: If the database backend cannot determine a precise mapping, it defaults to TextField with a # This field type is a guess. comment.

Troubleshooting and Gotchas

Name Normalization

When inspectdb encounters database names that are incompatible with Python or Django, it applies transformations in normalize_col_name:

  • Reserved Words: If a column is named class or pass, it becomes class_field or pass_field.
  • Invalid Identifiers: Columns starting with numbers are prefixed with number_.
  • Special Characters: Non-alphanumeric characters are replaced with underscores.
  • Conflicts: If normalization results in a name already used in the model, a numeric suffix is added (e.g., field_1).

In all these cases, the original database column name is preserved in the field's db_column attribute:

# Example of normalized field in generated models.py
my_field = models.CharField(max_length=255, db_column='My-Field') # Field renamed to remove unsuitable characters.

Settings Comparison False Positives

Because diffsettings compares the repr() of values, complex objects (like database engines or custom middleware classes) might appear as "changed" if their string representation includes volatile data like memory addresses, even if the configuration is logically identical to the default.

Database Support

Introspection is only available if the database backend supports it. The command checks connection.features.supports_inspectdb before running. If unsupported, it raises a CommandError.