Short version

I'm trying to run a custom migration (via RunPython) that involves an inherited model, say Restaurant. However a FieldError exception is raised at Restaurant.objects.all(), specifying that an inherited field cannot be resolved. Indeed the model returned by apps.get_model("myapp", "Restaurant") oddly does not inherit from the parent class.

Longer version

Context

Consider a Django multi-table inheritance where a model, say Restaurant(address, serves_pizza), inherits from a parent model, say Place(name). The fields for both models are indicated between brackets. The goal is to transfer a certain Restaurant field, say address, to the parent class Place. One challenge is to preserve the data by transferring it through a customized migration operation. One idea that I feel is rather straightforward is

  1. first create an intermediate field address_place in Place,
  2. then, manually move the data from Restaurant.address to Restaurant.address_place (via migrations.RunPython)
  3. finally remove address field and rename address_place into address

Focusing on 2., here is what the custom code called by RunPython looks like:

def transfer_address_from_restaurant_to_place(apps, schema_editor):
    Restaurant = apps.get_model("myapp", "Restaurant")
    for restau in Restaurant.objects.all():
        restau.address_place = restau.address
        restau.save()
FieldError, the unexpected error

However when running the corresponding migration, a FieldError exception is raised at for restau in Restaurant.objects.all() and looks like:

FieldError: Cannot resolve keyword 'name' into field. Choices are: address, serves_pizza

Yet Restaurant should have access to the fields of the parent class Place, that is name and address_place. In fact, if we examine the model Restaurant returned by apps.get_model, we can see that it does not inherit from the parent model Place at all, but simply from the base models.Model...

Hence

  • what can explain this, namely that apps.get_model does not preserve the inheritance?
  • and how to deal with it? or what other approach can be used to get around the problem and get the field address to the parent class?

Edit – how to reproduce the behavior

I think that this unexpected behavior comes from an older migration. A somewhat frustrating but workable solution would be to clean up the migration history as suggested by @boyenec.

First, I tried to reproduce the error on a minimal example. However everything worked fine: no FieldError was raised. By examining Restaurant from apps.get_model("myapp", "Restaurant"), it inherited as expected from Place. In this minimal example I directly started from two models that looked like this:

class Place(models.Model):
    name = ...

class Restaurant(Place):
    address = ...
    serves_pizza = ...

However this is not really representative of my migration history. Originally there was only Restaurant(name, address, serves_pizza). And I created its parent class a posteriori, with a migration similar to this idea. In this scenario the error I get is reproducible.

1

There are 1 best solutions below

0
Adrien Delhorme On

I got the same error and it was due to a Meta.ordering field on my model, which referenced a field that was transferred to the parent model.

In my models.py, I replaced:

class Meta:
  ordering = ["name"]

By:

class Meta:
  ordering = ["place_ptr__name"]

And created a migration for this change. After that my data migration ran without problems.