ImportError: cannot import name db from partially initialized module app (Circular Import)
Decouple the database instance into a standalone extensions.py / db.py module, or use the Application Factory pattern to break circular import dependencies.
Root Cause Analysis
This error occurs when Python tries to import a symbol (such as db or models) from a module that is currently in the middle of executing its top-level code, creating a cyclic dependency where module A imports module B which imports module A before module A has finished defining db.
Python's Module Import Lifecycle
When Python imports a module for the first time:
- An empty module object is created and inserted into
sys.modules. - Python begins executing the module's bytecode line by line from top to bottom.
- If line 5 encounters
from models import User, execution ofapp.pypauses and transfers immediately tomodels.py. - If
models.pyon line 1 executesfrom app import db, Python looks upappinsys.modules, finds the partially initialized module object, and checks fordb. - Since
app.pywas paused before reaching the line definingdb = SQLAlchemy()ordb = Database(), Python raisesImportError: cannot import name 'db' from partially initialized module 'app' (most likely due to a circular import).
Typical Architecture Traps
- Monolithic
app.pyimportingmodels.pyat top-level whilemodels.pyinherits fromdb.Modeldefined inapp.py. - Django apps importing each other's models at module level instead of using string references in ForeignKeys (
ForeignKey('app_b.ModelB')).
Reproduction Code (MCVE)
import sys
import types
# Simulates two modules with circular import dependency
mod_app = types.ModuleType('app')
sys.modules['app'] = mod_app # Registered in sys.modules before 'db' is assigned
# When models attempts to import 'db' from the unpopulated module, ImportError is raised
raise ImportError("cannot import name 'db' from partially initialized module 'app' (most likely due to a circular import)")
Solution 1: Decouple Database Instance into `extensions.py`
Create a separate extensions.py file containing only the unattached extension instance. Both app.py and models.py import from extensions.py, breaking the cycle.
class DatabaseExtension:
def __init__(self):
self.is_connected = False
def init_app(self, app_config: dict):
self.is_connected = True
print(f'Database initialized with: {app_config["DB_URI"]}')
# extensions.py: pure declaration with zero upward dependencies
db = DatabaseExtension()
# models.py imports db from extensions.py without touching app.py
class UserModel:
def __init__(self, username: str):
self.username = username
# app.py initializes the extension
db.init_app({'DB_URI': 'sqlite:///:memory:'})
print(f'User model created: {UserModel("alice").username}')
Solution 2: Use String Model References in Django Relationships
In Django models, reference related models using 'app_label.ModelName' strings instead of direct class imports.
# In Django models, avoid importing models directly for ForeignKeys:
# Bad: from orders.models import Order; customer = models.ForeignKey(Order, ...)
# Good: customer = models.ForeignKey('orders.Order', ...)
relationship_definition = {
'model': 'Customer',
'foreign_key_target': 'orders.Order',
'status': 'Resolved dynamically at Django app ready phase'
}
print(f'Relationship mapped without circular imports: {relationship_definition}')
Common Pitfalls & Edge Cases
A temporary hack often used is moving import models to the bottom of app.py. While this avoids the crash at import time, it creates fragile code that breaks as soon as a linter (like black or isort) reorders imports to the top of the file. Always use the extensions.py architecture.
Contrasting with related errors:
ImportError: cannot import name 'X' from partially initialized module: Circular dependency within project files.ModuleNotFoundError: No module named 'X': Module or file does not exist onsys.path.django.core.exceptions.AppRegistryNotReady: Models imported before Django app registry finishes loading.