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_place
inPlace
, - then, manually move the data from
Restaurant.address
toRestaurant.address_place
(viamigrations.RunPython
) - finally remove
address
field and renameaddress_place
intoaddress
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.