Let's imagine a following simplified Django project:
<root>/lib/python2.7/site-packages/externalapp/shop
<root>/myapp
myapp
also extends externalapp.shop.models
models by adding a few fields. manage.py makemigrations
did generated following schema migration file called 0004_auto_20150410_2001.py:
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
# __init__ is added by me as an attempt how to tell django's
# migration loader operations are for the different application
def __init__(self, name, app_label):
super(Migration, self).__init__(name, 'shop')
dependencies = [
('myapp', '__first__'),
('shop', '0003_auto_20150408_0958'),
]
operations = [
migrations.AddField(
model_name='product',
name='vat',
field=models.ForeignKey(to='myapp.VAT', null=True),
),
]
If the above migration schema is placed in <root>/lib/python2.7/site-packages/externalapp/shop/migrations/
path by default, manage.py migrate
succeeds and table fields are correctly added.
However if I do move the above migration file into myapp/migrations/
, following manage.py migrate
fails with
django.core.management.base.CommandError: Conflicting migrations detected (0001_initial, 0004_auto_20150410_2001 in myapp). To fix them run 'python manage.py makemigrations --merge'
error message I can't quite understand and suggested makemigrations --merge
fails with expected:
ValueError: Could not find common ancestor of set([u'0001_initial', u'0004_auto_20150410_2001'])
I've tried to override migrations.Migration.__init__
to alter derived app_label
but seems migration loader ignores it.
How adjust migration file so it can work from other application ?
The reason is in production externalapp
sources can't be directly touched, are read only.
Short answer: the migrations originate from Django apps and third party apps you installed in INSTALLED_APPS . Not the ones you defined yourself. Migrations are generated per app, and are stored in some_app/migrations .
makemigrations is responsible for packaging up your model changes into individual migration files - analogous to commits - and migrate is responsible for applying those to your database.
To move a migration file around a Django project, like in case of injecting models of other applications, you need to ensure in your django.db.migrations.Migration
descendant:
django_migrations
)I've solved the issue in migration initializer which may look like:
from django.db import migrations
TARGET_APP = 'shop' # application label migration is for
class Migration(migrations.Migration):
def __init__(self, name, app_label):
# overriding application operated upon
super(Migration, self).__init__(name, TARGET_APP)
# specify what original migration file it replaces
# or leave migration loader confused about unapplied migration
replaces = ((TARGET_APP, __module__.rsplit('.', 1)[-1]),)
It does work for me and find it enough generic way.
Eager to hear about a better/simpler solution if possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With