DavidRguez
DavidRguez

Reputation: 1110

Migrating from abstract model to proxy models

Right now, I have an abstract model with several models that inherits its fields. But I have discovered the power of Proxy models, and I want to implement them to my app. This is a picture from now:

class BaseModel(models.Model):
    field_1 = models.CharField(max_length=10)
    field_2 = models.CharField(max_length=10)
    field_3 = models.CharField(max_length=10)

    class Meta:
        abstract = True

class Model1(BaseModel):
    pass

    def __unicode__(self):
        return self.field_1

class Model2(BaseModel):
    pass

    def __unicode__(self):
        return self.field_1

And this is what I want:

class BaseModel(models.Model):
    field_1 = models.CharField(max_length=10)
    field_2 = models.CharField(max_length=10)
    field_3 = models.CharField(max_length=10)

class Model1(BaseModel):
    pass

    class Meta:
        proxy = True

    def __unicode__(self):
        return self.field_1

class Model2(BaseModel):
    pass

    class Meta:
        proxy = True

    def __unicode__(self):
        return self.field_1

The problem is when I remove the "abstract = True" sentence. When I try to migrate, this is the warning:

You are trying to add a non-nullable field 'basemodel_ptr' to Model1 without a default; we can't do that (the database needs something to populate existing rows).

Ok, got it. I read "ptr" is a pointer to the parent model, which is BaseModel, but I don't have any BaseModel, and I cannot get it until I migrate. How can I fix this??

Upvotes: 0

Views: 715

Answers (1)

Risadinha
Risadinha

Reputation: 16666

The migrations for this are not trivial.

Currently, your database has two tables:

  • yourapp_model1
  • yourapp_model2

Both have the same columns but they use different sequences meaning that their primary keys clash: Both of the tables will start counting their IDs (aka PKs) from 1 onwards. There is a very good chance that there is an instance of Model1 with pk=1 as well as an instance of Model2 with pk=1 and they are not the same.

This is the point of having an abstract model and concrete implementations: share Django code (business logic) while separating the data in the DB. For example, because it is semantically different (different types).

The point of proxy models is the exact opposite: while the data is located in one table in the DB, the proxy models allow you to implement different behaviour but based on the same DB data.

If you are now migrating from abstract models to proxy models it means that what you once considered different types will now become the same types (from a database point of view). As mentioned at the beginning, you will have to move the data from several tables into one and regenerate the IDs for at least part of it. Meaning also, that part of the resources that are currently using these URLs will change/cease to exist/point to a different resource.

Unless you can start from scratch (no live data that you have to support) you should really appreciate the magnitude of this change.

Should you not have the need to support live data:

  1. drop the database
  2. recreate the database
  3. remove all migration files
  4. recreate all migration files from scratch
  5. call migrate

Data migration of live data:

Note that there are other ways to do this. Search for "Django data migration".

  1. create the new Model structure with new names (no collisions)
  2. makemigrations which will now pick up the new model structure and create new and empty tables in database leaving the old tables and their data untouched
  3. create a management command that reads in the old model instances and copies them into the new tables
  4. once this command has been run on production you can deprecate the old models and remove them while making sure that everything that was depending on them is now using the new tables

Upvotes: 4

Related Questions