I’m working on a Django Project that currently uses the third party app Oscar. We’re in the process of migrating away from Oscar, to a custom-built shop, and for this we want to get rid of a bunch of old files, models and of course the actual third party dependencies. But I am having a hard time doing this because the migration files keep throwing up errors.
The situation is that we have first-party models that depend on Oscar’s models. For example:
from oscar.apps.catalogue.models import Product
class Executable(Model):
exec_hash = CharField(max_length=64, unique=True)
product = ForeignKey(Product, blank=True, null=True, on_delete=CASCADE)
version = CharField(max_length=32)
os = CharField(max_length=32)
update_url = CharField(max_length=128, blank=True)
This means we have a migration file that contains the code to create this table:
migrations.CreateModel(
name="Executable",
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("exec_hash", models.CharField(max_length=64, unique=True)),
("version", models.CharField(max_length=32)),
("os", models.CharField(max_length=32)),
("update_url", models.CharField(blank=True, max_length=128)),
(
"product",
models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="catalogue.product"
),
),
],
),
The product
field from this Executable
needs to be removed, so I removed the field from the model and created a new migration.
Now I want to remove all the Oscar apps from my INSTALLED_APPS
list, but this is causing a whole lot of headaches because when I want to create or run any migration, I get this error:
ValueError: The field sr_app.Executable.product was declared with a lazy reference to 'catalogue.product', but app 'catalogue' isn't installed.
I’ve tried to simply remove this field from the initial migration file, but then in the next migration (where this field is actually being removed from the model), I get a key error:
Running migrations:
Applying sr_app.0003_remove_executable_product...Traceback (most recent call last):
[...snip...]
File "/Users/kevin/Workspace/my_project_name/.venv/lib/python3.10/site-packages/django/db/migrations/operations/fields.py", line 162, in state_forwards
old_field = model_state.fields.pop(self.name)
KeyError: 'product'
So it seems that I have to keep Oscar installed and part of INSTALLED_APPS
forever, because the initial migration uses this info? But this first migration is applied already, so it’s kind of annoying that the initial migration needs to be valid for the next one to run.
How can I get around this problem? How can I get rid of Oscar (or any third party app) when my own initial migrations spend on that third party app?
It almost seems easier to nuke all the migrations, create a brand new one for the new state, and manually make all the database changes (it’s just dropping tables and columns, so doable). Then fake-apply the migration. But surely there must be a better way that’s reproducible on our server 🤔