如何拆分Django电商项目为买家/卖家/Admin子项目并同步共享模型?
Great question—this is a super common pain point when splitting a monolithic Django e-commerce app into specialized buyer, seller, and admin services while keeping core domain models in sync. Let’s walk through practical, maintainable solutions to manage shared schemas without pulling your hair out:
1. Extract Shared Models into a Reusable Core Package
First, you never want to copy-paste identical model code across three projects—that’s a sync nightmare waiting to happen. Pull all core models used by all three services (like Product, Category, Order, or base User info) into a standalone Python package, e.g., ecommerce-core.
- Example directory structure:
ecommerce-core/ pyproject.toml # Manage dependencies & packaging with Poetry/Setuptools ecommerce_core/ __init__.py models/ __init__.py product.py category.py order.py migrations/ __init__.py # Migration files will be generated here centrally - Install this package in each subproject’s virtual environment: use
pip install -e ../ecommerce-corefor local development, or pull from a private Git repo/PyPI for production. - Add
ecommerce_coretoINSTALLED_APPSin each subproject’ssettings.pyso Django recognizes these shared models.
2. Centralize Migration Management
Schema changes to shared models must be controlled from one place—no per-project migration generation allowed. Here’s the workflow:
- When you modify a model in
ecommerce-core, generate migrations from the core package directory:- Add a minimal Django setup (a
manage.pyand stripped-downsettings.py) to the core package just for migration generation. Runpython manage.py makemigrations ecommerce_coreto create migration files in the core package’smigrationsfolder.
- Add a minimal Django setup (a
- Push the updated core package to your version control system (Git), then pull the latest version in all three subprojects.
- Apply migrations to each subproject’s database:
- If your subproject uses multiple databases, specify the target alias:
python manage.py migrate ecommerce_core --database=buyer_db(for the buyer project),python manage.py migrate ecommerce_core --database=seller_db(seller project), etc. - To skip typing
--databaseevery time, use a database router (see next step).
- If your subproject uses multiple databases, specify the target alias:
3. Use Database Routers to Simplify Migrations
A database router automatically directs shared model operations (read/write/migrate) to the correct database, eliminating manual flags. Here’s an example for the buyer project:
- Create
routers.pyin the buyer project:class CoreModelRouter: def db_for_read(self, model, **hints): # Route shared model reads to the buyer database if model._meta.app_label == 'ecommerce_core': return 'default' # Default DB is the buyer's database return None def db_for_write(self, model, **hints): # Route shared model writes to the buyer database if model._meta.app_label == 'ecommerce_core': return 'default' return None def allow_migrate(self, db, app_label, model_name=None, **hints): # Only allow migrations for shared models on the buyer database if app_label == 'ecommerce_core': return db == 'default' return None - Add the router to the buyer project’s
settings.py:DATABASE_ROUTERS = ['buyers_project.routers.CoreModelRouter'] - Now running
python manage.py migrate ecommerce_corewill automatically apply changes to the buyer’s database. Repeat this router setup for the seller and admin projects, pointing to their respective databases.
4. Enforce Consistency with CI/CD Checks
Prevent missed migrations or schema drift with automated checks in your CI/CD pipeline:
- Add a step to each subproject’s deployment workflow that runs
python manage.py migrate --check. If there are unapplied migrations, block deployment and alert the team. - For strict consistency, add a script that compares the schema of all three databases (e.g., using
django-inspectdbto export schemas and diff them) to ensure core model structures match across all services.
5. Handle Model Extensions Without Breaking Sync
If a subproject needs to add service-specific fields to a shared model (e.g., admins need internal product notes), don’t modify the core model. Instead, use a OneToOneField to link to a subproject-specific extension model:
# admins_project/models.py from django.db import models from ecommerce_core.models import Product class AdminProductExtension(models.Model): product = models.OneToOneField(Product, on_delete=models.CASCADE, related_name='admin_extension') internal_notes = models.TextField(blank=True) approval_status = models.CharField(max_length=20, choices=[('pending', 'Pending'), ('approved', 'Approved')])
This keeps the core model clean while letting each service add its own functionality without affecting the others.
Finally, use semantic versioning for the ecommerce-core package (e.g., v1.0.1 → v1.0.2 for schema changes) and have each subproject depend on a specific version. This prevents accidental, untested schema changes from breaking your services.
内容的提问来源于stack exchange,提问作者Afsal KK

