Usage Guide for modelfilters¶
Overview¶
The modelfilters management command helps developers understand and navigate complex Django model relationships by displaying all possible field paths between models.
For example, using models from the example project, running:
python manage.py modelfilters sales.ShippingAddress
Would show all possible filtering paths starting from the ShippingAddress model in the sales app (178 in total):
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
city |
ShippingAddress |
city |
CharField |
sales.ShippingAddress |
country |
ShippingAddress |
country |
CharField |
sales.ShippingAddress |
created_at |
ShippingAddress |
created_at |
DateTimeField |
sales.ShippingAddress |
customer |
ShippingAddress |
customer |
ForeignKey |
sales.ShippingAddress |
customer__company_name |
Customer |
company_name |
CharField |
sales.ShippingAddress,common.Customer |
customer__created_at |
Customer |
created_at |
DateTimeField |
sales.ShippingAddress,common.Customer |
customer__credit_limit |
Customer |
credit_limit |
DecimalField |
sales.ShippingAddress,common.Customer |
customer__id |
Customer |
id |
BigAutoField |
sales.ShippingAddress,common.Customer |
customer__is_active |
Customer |
is_active |
BooleanField |
sales.ShippingAddress,common.Customer |
… |
This tool is particularly useful when:
Building complex database queries (e.g., finding all possible ways to join to a User model)
Creating reports that span multiple related models
Understanding the relationship structure of a large Django application
Identifying available fields for filtering and annotations
Helping generative AI to better understand the relationships in your project
Command Syntax¶
python manage.py modelfilters [options]
Options¶
Filtering Options¶
positional arg: One or more app name(s), model name(s), or
app.Modelsyntax to evaluate. Here we are evaluating all models in theauthapp, thesales.Ordermodel and theCustomermodel (e.g.:common.Customer).python manage.py modelfilters auth sales.Order Customer
--target-model: Filter paths leading to a specific modelpython manage.py modelfilters sales --target-model User python manage.py modelfilters sales --target-model auth.User
--target-field: Filter paths leading to a specific model fieldpython manage.py modelfilters sales --target-field email
--target-field-type: Filter by field typepython manage.py modelfilters sales --target-field-type DateTimeField
-e, --exclude: Exclude specific apps, models, or fieldspython manage.py modelfilters sales -e auth Permission python manage.py modelfilters sales -e customer__sales_creditcards customer__user
--prefix: Include only models/fields in a path with a specific prefixpython manage.py modelfilters sales --prefix Customer
Path Limiting Options¶
--max-depth: Limit the number of relationship traversals (default: 4)python manage.py modelfilters sales --max-depth 3
--max-paths: Limit the maximum number of paths returned for each model of interestpython manage.py modelfilters sales --max-paths 10
Sorting Options¶
--by-depth: Sort results by number of relationship traversals--by-model: Sort results by related model name
Output Options¶
-m, --markdown: Output in markdown format-o, --output: Export results to a file (supports .txt, .html, .htm, .md)
Cache Control¶
--use-cache: Use cached results if available (see also settings)--clear-cache: Clear cached results before running
Settings¶
All settings are optional, and should be added as dictionary key-value entries in the DJANGO_MODELINFO setting.
CACHE_ENABLED: bool Enable caching of results (default: False)CACHE_ALWAYS: bool Always cache results, even if the –use-cache flag is not used (default: False)CACHE_ALIAS: str The cache alias to use for caching results (default: “default”)CACHE_TIMEOUT: int The cache timeout in seconds (default: 3600)CACHE_KEY_PREFIX: str The prefix to use for cache keys (default: “modelfilters:”)
Understanding Output¶
The command outputs a table with five columns:
Field Path: The full path to the field using Django’s double-underscore notation
Model: The model containing the field
Field Name: The name of the field
Field Type: The Django field type
Models in Path: All of the models involved in the filter path
Example outputs for different filtering scenarios:
Basic Model Fields¶
python manage.py modelfilters auth.User --by-depth
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
customer |
User |
customer |
OneToOneRel |
auth.User |
date_joined |
User |
date_joined |
DateTimeField |
auth.User |
User |
EmailField |
auth.User |
||
first_name |
User |
first_name |
CharField |
auth.User |
groups |
User |
groups |
ManyToManyField |
auth.User |
id |
User |
id |
AutoField |
auth.User |
… |
Filtering by Field Type¶
python manage.py modelfilters sales.ShippingAddress --target-field-type DateTimeField
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
created_at |
ShippingAddress |
created_at |
DateTimeField |
sales.ShippingAddress |
customer__created_at |
Customer |
created_at |
DateTimeField |
sales.ShippingAddress,common.Customer |
customer__orders__created_at |
Order |
created_at |
DateTimeField |
sales.ShippingAddress,common.Customer,sales.Order |
customer__orders__items__created_at |
OrderItem |
created_at |
DateTimeField |
sales.ShippingAddress,common.Customer,sales.Order,sales.OrderItem |
customer__orders__items__updated_at |
OrderItem |
updated_at |
DateTimeField |
sales.ShippingAddress,common.Customer,sales.Order,sales.OrderItem |
customer__orders__order_date |
Order |
order_date |
DateTimeField |
sales.ShippingAddress,common.Customer,sales.Order |
… |
Advanced Features¶
Combining Filters¶
You can combine multiple filters for precise results:
python manage.py modelfilters \
sales \
--target-model User \
--target-field-type EmailField \
--max-depth 3 \
--exclude auth
Using Export Formats¶
Different export formats serve different purposes:
.md: Documentation and GitHub.html: Web viewing.txt: Simple text processing
Using modelfilters: A Practical Guide¶
In this section, we’ll explore how to use the modelfilters command to help build efficient queries across related models in our application that handles customer orders, inventory, and analytics.
Example Models Overview¶
Our example project manages inventory, sales, and analytics with several interconnected models. Here’s a key subset of the relationships:
# common/models.py
class Customer(BaseModel):
user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
phone = models.CharField(max_length=20, blank=True)
company_name = models.CharField(max_length=200, blank=True)
tax_id = models.CharField(max_length=50, blank=True)
notes = models.TextField(blank=True)
credit_limit = models.DecimalField(max_digits=10, decimal_places=2, default=0)
# sales/models.py
class Order(BaseModel):
STATUS_CHOICES = [
("pending", "Pending"),
("processing", "Processing"),
("shipped", "Shipped"),
("delivered", "Delivered"),
("cancelled", "Cancelled"),
]
customer = models.ForeignKey(Customer, on_delete=models.PROTECT, related_name="orders")
order_number = models.CharField(max_length=50, unique=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
order_date = models.DateTimeField(auto_now_add=True)
shipping_address = models.ForeignKey("ShippingAddress", on_delete=models.PROTECT)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
notes = models.TextField(blank=True)
# inventory/models.py
class Product(BaseModel):
name = models.CharField(max_length=200)
sku = models.CharField(max_length=50, unique=True)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
suppliers = models.ManyToManyField(Supplier, through="ProductSupplier", related_name="products")
weight = models.DecimalField(max_digits=8, decimal_places=2, help_text="Weight in kilograms", null=True, blank=True)
Example Use Cases¶
2. Product Supply Chain Analysis¶
For inventory management, we need to understand product relationships with suppliers and categories:
python manage.py modelfilters inventory.Product --by-depth
The output reveals the product relationship hierarchy:
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
category |
Product |
category |
ForeignKey |
inventory.Product |
created_at |
Product |
created_at |
DateTimeField |
inventory.Product |
description |
Product |
description |
TextField |
inventory.Product |
id |
Product |
id |
BigAutoField |
inventory.Product |
is_active |
Product |
is_active |
BooleanField |
inventory.Product |
name |
Product |
name |
CharField |
inventory.Product |
orderitem |
Product |
orderitem |
ManyToOneRel |
inventory.Product |
performance_metrics |
Product |
performance_metrics |
ManyToOneRel |
inventory.Product |
… |
||||
productsupplier__cost |
ProductSupplier |
cost |
DecimalField |
inventory.Product,inventory.ProductSupplier |
productsupplier__created_at |
ProductSupplier |
created_at |
DateTimeField |
inventory.Product,inventory.ProductSupplier |
productsupplier__id |
ProductSupplier |
id |
BigAutoField |
inventory.Product,inventory.ProductSupplier |
productsupplier__is_active |
ProductSupplier |
is_active |
BooleanField |
inventory.Product,inventory.ProductSupplier |
productsupplier__is_preferred |
ProductSupplier |
is_preferred |
BooleanField |
inventory.Product,inventory.ProductSupplier |
productsupplier__lead_time_days |
ProductSupplier |
lead_time_days |
PositiveIntegerField |
inventory.Product,inventory.ProductSupplier |
… |
Using these paths, we can analyze product supply chain metrics:
# Find products with multiple suppliers and their cost variations
from example_project.inventory.models import Product
from django.db.models import Avg, Count, Min
Product.objects.annotate(
supplier_count=Count('suppliers'),
avg_cost=Avg('productsupplier__cost'),
min_lead_time=Min('productsupplier__lead_time_days')
).filter(
supplier_count__gt=1
).select_related('category')
3. Sales Performance Analytics¶
To analyze sales performance, let’s explore all available metrics fields:
python manage.py modelfilters analytics.SalesMetrics
Output shows available metrics:
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
average_order_value |
SalesMetrics |
average_order_value |
DecimalField |
analytics.SalesMetrics |
conversion_rate |
SalesMetrics |
conversion_rate |
DecimalField |
analytics.SalesMetrics |
created_at |
SalesMetrics |
created_at |
DateTimeField |
analytics.SalesMetrics |
date |
SalesMetrics |
date |
DateField |
analytics.SalesMetrics |
id |
SalesMetrics |
id |
BigAutoField |
analytics.SalesMetrics |
is_active |
SalesMetrics |
is_active |
BooleanField |
analytics.SalesMetrics |
notes |
SalesMetrics |
notes |
TextField |
analytics.SalesMetrics |
total_orders |
SalesMetrics |
total_orders |
IntegerField |
analytics.SalesMetrics |
… |
This helps us build comprehensive sales analysis queries:
# Analyze sales trends with rolling averages
from example_project.analytics.models import SalesMetrics
from django.db.models import Avg, F, RowRange, Window
SalesMetrics.objects.annotate(
rolling_avg_orders=Window(
expression=Avg('total_orders'),
order_by=F('date').asc(),
frame=RowRange(start=-6, end=0)
),
rolling_conversion=Window(
expression=Avg('conversion_rate'),
order_by=F('date').asc(),
frame=RowRange(start=-6, end=0)
)
).order_by('-date')
Complex Model Relationship Example¶
Let’s build a complex query that analyzes product performance across our entire system, including sales, inventory, and customer data. This example makes use of the data provided in the included fixtures. Run the following command to load the fixtures:
python manage.py loaddata data
The Challenge¶
Based in the models in our example project, we want to create a comprehensive product analysis that includes:
Sales performance metrics
Inventory status
Supplier relationships
Customer purchasing patterns
Using modelfilters to Discover Paths¶
First, let’s find all paths from Product to our analytics:
python manage.py modelfilters inventory.Product --target-model ProductPerformance
This reveals the connections:
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
performance_metrics__created_at |
ProductPerformance |
created_at |
DateTimeField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__date |
ProductPerformance |
date |
DateField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__id |
ProductPerformance |
id |
BigAutoField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__is_active |
ProductPerformance |
is_active |
BooleanField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__notes |
ProductPerformance |
notes |
TextField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__product |
ProductPerformance |
product |
ForeignKey |
inventory.Product,analytics.ProductPerformance |
performance_metrics__profit_margin |
ProductPerformance |
profit_margin |
DecimalField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__revenue |
ProductPerformance |
revenue |
DecimalField |
inventory.Product,analytics.ProductPerformance |
performance_metrics__units_sold |
ProductPerformance |
units_sold |
PositiveIntegerField |
inventory.Product,analytics.ProductPerformance |
… |
Now let’s find order and customer related paths:
python manage.py modelfilters inventory.Product --target-model Order OrderItem Customer
Output shows order connections:
Field Path |
Model |
Field Name |
Field Type |
Models in Path |
|---|---|---|---|---|
… |
||||
orderitem__order |
OrderItem |
order |
ForeignKey |
inventory.Product,sales.OrderItem |
orderitem__product |
OrderItem |
product |
ForeignKey |
inventory.Product,sales.OrderItem |
orderitem__quantity |
OrderItem |
quantity |
PositiveIntegerField |
inventory.Product,sales.OrderItem |
orderitem__unit_price |
OrderItem |
unit_price |
DecimalField |
inventory.Product,sales.OrderItem |
… |
||||
orderitem__updated_at |
OrderItem |
updated_at |
DateTimeField |
inventory.Product,sales.OrderItem |
orderitem__order__created_at |
Order |
created_at |
DateTimeField |
inventory.Product,sales.OrderItem,sales.Order |
orderitem__order__customer |
Order |
customer |
ForeignKey |
inventory.Product,sales.OrderItem,sales.Order |
… |
||||
orderitem__order__total_amount |
Order |
total_amount |
DecimalField |
inventory.Product,sales.OrderItem,sales.Order |
orderitem__order__updated_at |
Order |
updated_at |
DateTimeField |
inventory.Product,sales.OrderItem,sales.Order |
orderitem__order__customer__company_name |
Customer |
company_name |
CharField |
inventory.Product,sales.OrderItem,sales.Order,common.Customer |
… |
Building the Analysis Query¶
Using the discovered paths, we can build a comprehensive analysis:
import textwrap
from example_project.inventory.models import Product
from django.db.models import Avg, Count, Min, Sum, F, Q, Window
from django.db.models.functions import TruncMonth
from django.utils import timezone
# Comprehensive product analysis
current_year = timezone.now().year
report_rows = Product.objects.annotate(
# Sales metrics
total_orders=Count('orderitem__order', distinct=True),
total_revenue=Sum(F('orderitem__unit_price') * F('orderitem__quantity')),
# Performance metrics
avg_monthly_units=Avg(
'performance_metrics__units_sold',
filter=Q(performance_metrics__date__year=current_year)
),
avg_profit_margin=Avg(
'performance_metrics__profit_margin',
filter=Q(performance_metrics__date__year=current_year)
),
# Supplier metrics
supplier_count=Count('suppliers', distinct=True),
avg_lead_time=Avg('productsupplier__lead_time_days'), # See previous section
min_cost=Min('productsupplier__cost'),
# Customer insights
unique_customers=Count(
'orderitem__order__customer',
distinct=True
),
corporate_orders=Count(
'orderitem__order',
filter=Q(orderitem__order__customer__company_name__isnull=False),
distinct=True
)
).select_related(
'category'
).prefetch_related(
'suppliers',
'performance_metrics'
).order_by('-total_revenue')
# Format and print the report using the standard library
for row in report_rows:
# Handle None values explicitly before formatting
total_revenue = f"{row.total_revenue:.2f}" if row.total_revenue is not None else "0"
avg_monthly_units = f"{row.avg_monthly_units:.2f}" if row.avg_monthly_units is not None else "N/A"
avg_profit_margin = f"{row.avg_profit_margin:.2%}" if row.avg_profit_margin is not None else "N/A"
avg_lead_time = f"{row.avg_lead_time:.1f}" if row.avg_lead_time is not None else "N/A"
min_cost = f"{row.min_cost:,.2f}" if row.min_cost is not None else "N/A"
output = textwrap.dedent(f"""
Product: {row.name}
────────────────────────────────────────────
Sales Metrics:
• Total Orders : {row.total_orders:,}
• Total Revenue : ${total_revenue}
• Average Monthly Units : {avg_monthly_units}
• Average Profit Margin : ${avg_profit_margin}
Supplier Metrics:
• Supplier Count : {row.supplier_count}
• Average Lead Time : {avg_lead_time} days
• Minimum Cost : ${min_cost}
Customer Insights:
• Unique Customers : {row.unique_customers:,}
• Corporate Orders : {row.corporate_orders:,}
────────────────────────────────────────────
""")
print(output)
Here is the output for the first couple items in the report:
Product: Blender Max
────────────────────────────────────────────
Sales Metrics:
• Total Orders : 9
• Total Revenue : $8707.32
• Average Monthly Units : 40.00
• Average Profit Margin : $2400.00%
Supplier Metrics:
• Supplier Count : 3
• Average Lead Time : 13.3 days
• Minimum Cost : $120.00
Customer Insights:
• Unique Customers : 6
• Corporate Orders : 9
────────────────────────────────────────────
Product: Washing Machine Z
────────────────────────────────────────────
Sales Metrics:
• Total Orders : 9
• Total Revenue : $6900.00
• Average Monthly Units : 30.00
• Average Profit Margin : $2200.00%
Supplier Metrics:
• Supplier Count : 4
• Average Lead Time : 17.8 days
• Minimum Cost : $400.00
Customer Insights:
• Unique Customers : 5
• Corporate Orders : 9
────────────────────────────────────────────
This query provides a complete view of:
Product sales performance
Supplier diversity and cost efficiency
Customer segment analysis
Historical performance trends
Performance Tips¶
Use Caching
Enable caching for repeated queries:
--use-cacheClear cache when needed:
--clear-cache
Limit Search Space
Set appropriate
--max-depthUse
--max-pathsfor large applications
Filter Early
Use
--target-modeland--target-fieldwhen possibleApply
--excludefor known irrelevant paths or modelsUse
--prefixto focus on specific model sets
Troubleshooting Common Issues¶
Too Many Results
Use
--max-pathsto limit outputAdd specific filters
Increase
--max-depthgradually
Missing Paths
Check
--max-depthisn’t too lowVerify excluded paths with
-e/--excludeEnsure target model/field names are correct