The problem
A healthcare startup's Django project had 147 database migrations that took 12 minutes to run. The database contained User, AppUser, UserProfile, CustomerUser, and AccountUser models - all storing essentially the same data. Every new feature created migration conflicts requiring manual resolution. The 84GB PostgreSQL database was 70% duplicate data across redundant tables.
How AI created this issue
Different developers had asked ChatGPT to create models for various features over 6 months. Each time, ChatGPT generated new models without checking existing ones:
# Developer 1: "Create a user model for authentication"
# ChatGPT response:
class AppUser(models.Model):
email = models.EmailField(unique=True)
username = models.CharField(max_length=150)
password = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=True)
# Developer 2: "I need a customer profile model"
# ChatGPT response:
class CustomerUser(models.Model):
email_address = models.EmailField(unique=True)
full_name = models.CharField(max_length=255)
password_hash = models.CharField(max_length=255)
registration_date = models.DateTimeField(auto_now_add=True)
class UserProfile(models.Model):
user_email = models.EmailField(unique=True)
display_name = models.CharField(max_length=200)
bio = models.TextField(blank=True)
# Developer 3: "Add user accounts for billing"
# ChatGPT response:
class AccountUser(models.Model):
account_email = models.EmailField(unique=True)
account_name = models.CharField(max_length=255)
encrypted_password = models.CharField(max_length=255)
signup_timestamp = models.DateTimeField(auto_now_add=True)
ChatGPT never asked "Do you already have a user model?" It generated new models each time, creating a maze of foreign keys, duplicate data, and conflicting business logic spread across multiple tables.
The solution
- Model audit and mapping: Created a comprehensive map of all models and their relationships
- Data consolidation plan: Designed a single, extensible user model:
# Consolidated user model from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True, db_index=True) full_name = models.CharField(max_length=255) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) date_joined = models.DateTimeField(auto_now_add=True) # Profile fields (previously in separate models) bio = models.TextField(blank=True) avatar_url = models.URLField(blank=True) # Billing fields (previously in AccountUser) stripe_customer_id = models.CharField(max_length=255, blank=True) subscription_status = models.CharField(max_length=50, default='free') USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['full_name'] class Meta: db_table = 'users' indexes = [ models.Index(fields=['email', 'is_active']), models.Index(fields=['date_joined']), ]
- Migration strategy: Created a careful data migration preserving all relationships:
# Data migration to consolidate users def consolidate_users(apps, schema_editor): User = apps.get_model('accounts', 'User') AppUser = apps.get_model('legacy', 'AppUser') CustomerUser = apps.get_model('legacy', 'CustomerUser') # Map and migrate all user data for app_user in AppUser.objects.all(): User.objects.update_or_create( email=app_user.email, defaults={ 'full_name': app_user.username, 'date_joined': app_user.created_at, # Map other fields... } )
- Foreign key updates: Systematically updated all references to point to the new model
- Cleanup migrations: Squashed 147 migrations down to 23 essential ones
The results
- Database size reduced from 84GB to 31GB (63% reduction)
- Migration time dropped from 12 minutes to 47 seconds
- Query performance improved 4.2x with proper indexes
- Zero migration conflicts in 6 months (was 2-3 per week)
- Development velocity increased 35% with cleaner data model
- Test suite runs 3x faster without redundant model operations
The team implemented a "model registry" where all Django models are documented. New developers must check existing models before creating new ones. They learned that AI tools generate code in isolation - human architects must maintain the bigger picture.
Ready to fix your codebase?
Let us analyze your application and resolve these issues before they impact your users.
Get Diagnostic Assessment →