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
- first create an intermediate field
address_placeinPlace, - then, manually move the data from
Restaurant.addresstoRestaurant.address_place(viamigrations.RunPython) - finally remove
addressfield and renameaddress_placeintoaddress
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_modeldoes 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
addressto 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.