0

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.

nonin
  • 704
  • 4
  • 10
  • The error saying there is no fields `name` in your model you have `address, serves_pizza` fields in your model but there is no fields `name`. where you getting this error during run migration or search query from your function? – boyenec Jan 07 '22 at 16:43
  • The error is raised when running the migration at `for restau in Restaurant.objects.all()`. Note that there is no direct call to `Restaurant.name`. Nevertheless, since `Restaurant` inherits from `Place`, the attributes `address, serves_pizza, name` should be accessible. I'm thinking about a weird conflict that happens because of the fact that the `Restaurant` returned by `apps.get_model` does not inherit from `Place` ; when it should. – nonin Jan 07 '22 at 16:48
  • try to run migrations after delete your all migrations folders and file. – boyenec Jan 07 '22 at 17:01
  • Indeed I'm starting to think that it comes from a previous migration – nonin Jan 07 '22 at 17:02
  • 1
    yeah try to run migrations after delete your all migrations folder and file then if you are getting same problems then please add your resturent and place model in your question. – boyenec Jan 07 '22 at 17:05

1 Answers1

0

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.