Django Dynamic Model Creation
Why Create Models dynamically?
Creating models dynamically can be helpful in situations where the database schema is not known at development time, or if it can change during runtime.
Django allows us to define and manipulate database tables at runtime, which is quite different from the traditional approach of defining models statically in the code. This can be particularly useful for applications that dynamically adapt to varying database schemas based on external conditions or user inputs.
Implementation of Dynamic Models
In Django, models are usually defined as classes that inherit from django.db.models.Model, where each class represents a table in the database.
For a static model example in models.py,
from django.db import models.Model
class Employee(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
date_joined = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
However, dynamic models are created at runtime using Python’s type function instead of being written in the models.py file. This allows models to be generated programmatically based on the database structure.
The type() function is commonly used to return the type of an object, but it can also be used to create new types dynamically. The syntax for type() when used to create classes is
type(classname, superclasses, attributes_dict)
- classname: string defining the class name
- superclasses: a tuple defining the parent classes from which the new class inherits.
- attributes_dict: a dictionary containing the attributes and methods of the class, where keys are attribute/method names and values are attribute values or method functions.

These are the only steps you need to follow.
- First, we need to fetch the table details from the database dynamically.
(Here I use PostgreSQL and Oracle databases)
PostgreSQL has an information schema consisting of a set of views that contain information about the objects defined in the database, such as information_schema.tables, which provides table names and other details as well. Oracle has a view namedall_tables, which provides table names and other details.
# app_name/models.py
from django.db import connections
from django.conf import settings
def get_tables(db_alias, schema_name):
"""Retrieves table names from the given database schema."""
connection = connections[db_alias]
with connection.cursor() as cursor:
if db_alias in settings.ORACLE_DB_LIST:
cursor.execute(f"SELECT table_name FROM all_tables WHERE owner = '{schema_name}'")
elif db_alias in settings.POSTGRESQL_DB_LIST:
cursor.execute(f"SELECT table_name FROM information_schema.tables WHERE table_schema = '{schema_name.lower()}'")
return [row[0] for row in cursor.fetchall()]
2. Then fetch the column details of each table for use in Django fields
# app_name/models.py
def get_column_details(db_alias, schema_name, table_name):
"""Fetches column names and types from the database table."""
connection = connections[db_alias]
with connection.cursor() as cursor:
if db_alias in settings.ORACLE_DB_LIST:
cursor.execute(f"SELECT COLUMN_NAME, DATA_TYPE FROM all_tab_columns WHERE table_name=UPPER('{table_name}') AND owner = UPPER('{schema_name}')")
elif db_alias in settings.POSTGRESQL_DB_LIST:
cursor.execute(f"SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = '{schema_name.lower()}' AND table_name = '{table_name.lower()}'")
return cursor.fetchall()
3. Mapping database data types to Django fields
# app_name/models.py
from django.db import models
def map_data_type_to_django_field(data_type):
"""Maps database column types to Django model fields."""
mapping = {
'VARCHAR2': models.CharField,
'CHAR': models.CharField,
'TEXT': models.TextField,
'INTEGER': models.IntegerField,
'BIGINT': models.BigIntegerField,
'SMALLINT': models.SmallIntegerField,
'FLOAT': models.FloatField,
'DOUBLE': models.FloatField,
'DECIMAL': models.DecimalField,
'NUMERIC': models.DecimalField,
'DATE': models.DateField,
'TIMESTAMP': models.DateTimeField,
'BOOLEAN': models.BooleanField
}
return mapping.get(data_type.upper(), models.CharField)
4. Retrieving the primary key for each table
# app_name/models.py
def get_primary_key(db_alias, schema_name, table_name):
"""Retrieves the primary key of a database table."""
connection = connections[db_alias]
with connection.cursor() as cursor:
if db_alias in settings.ORACLE_DB_LIST:
cursor.execute(f"""
SELECT cols.column_name
FROM all_constraints cons, all_cons_columns cols
WHERE cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = UPPER('{schema_name}')
AND cols.table_name = UPPER('{table_name}')
""")
elif db_alias in settings.POSTGRESQL_DB_LIST:
cursor.execute(f"""
SELECT kcu.column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
WHERE tc.table_schema = '{schema_name.lower()}'
AND tc.table_name = '{table_name.lower()}'
AND tc.constraint_type = 'PRIMARY KEY'
""")
result = cursor.fetchall()
return result[0][0] if result else None
The Moment You’ve Been Waiting For,
5. Creating the dynamic model,
# app_name/models.py
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
def create_dynamic_model(table_name, db_alias, schema_name, app_label):
"""Dynamically creates a Django model from a database table."""
columns = get_column_details(db_alias, schema_name, table_name)
primary_key = get_primary_key(db_alias, schema_name, table_name)
fields = {
'__module__': __name__,
'Meta': type('Meta', (), {
'managed': False,
'db_table': f'"{schema_name}"."{table_name}"',
'app_label': app_label,
}),
}
# If there is no primary key for the table
if not primary_key:
fields['id'] = models.AutoField(primary_key=True)
for column, data_type in columns:
field_class = map_data_type_to_django_field(data_type)
field_params = {'max_length': 255} if issubclass(field_class, models.CharField) else {}
if issubclass(field_class, models.DecimalField):
field_params['max_digits'] = 10
field_params['decimal_places'] = 2
fields[column] = field_class(primary_key=(column == primary_key), **field_params)
model_name = table_name.replace(' ', '_').replace('.', '_').capitalize()
DynamicModel = type(model_name, (models.Model,), fields)
# Registers the dynamically created model in the Django admin interface.
register_dynamic_model(DynamicModel, db_alias)
return DynamicModel
6. Registering the dynamic model in Django admin
# app_name/admin.py
from django.contrib import admin
from django.db import models
from django.apps import apps
def register_dynamic_model(model, db_alias):
class DynamicAdmin(admin.ModelAdmin):
"""Custom Admin class for dynamic models."""
model._meta.db_table = support_database(model._meta.db_table)
def get_queryset(self, request):
return super().get_queryset(request).using(db_alias)
# Auto-generate list display and search fields based on model fields
list_display = [field.name for field in model._meta.fields if hasattr(field, 'name')]
search_fields = [field.name for field in model._meta.fields if isinstance(field, models.CharField) and hasattr(field, 'name')]
list_filter = [field.name for field in model._meta.fields if isinstance(field, models.BooleanField) and hasattr(field, 'name')]
# Register the model with the specified admin site
admin_site.register(model, DynamicAdmin)
7. Setting AppConfig for Dynamic Models
# app_name/apps.py
from django.apps import AppConfig
class DynamicModelAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
db_alias = 'your_db_alias'
schema_name = 'your_schema_name'
table_name = 'your_table_name'
# Generate a dynamic base name for the app
base_name = f"{db_alias.title().replace(' ', '')}.{db_alias.title().replace(' ', '')}_{schema_name.title().replace(' ', '')}"
name = f"{base_name}"
# Label for the app, typically used for model registration
label = f"{db_alias.lower()}_{schema_name.lower()}".strip()
def ready(self):
from .models import create_dynamic_models
create_dynamic_models(self.table_name, self.db_alias, self.schema_name, self.label)
Dynamic model creation in Django is a powerful technique that allows applications to adapt to evolving database structures without requiring manual code updates. By using Python’s type() function and Django’s ORM, we can generate models on the fly, making our applications more flexible and scalable.
This approach is particularly useful for systems that interact with multiple databases, deal with user-defined schemas, or require real-time adaptability. However, with great power comes great responsibility — always ensure that dynamically generated models align with your security, performance, and maintainability goals.
Whether you’re working with PostgreSQL, Oracle, or any other database, dynamically creating models unlocks a world of possibilities. Experiment with this technique, refine it to your needs, and take your Django projects to the next level!