Django - django.core.exceptions.FieldDoesNotExist - has no field named

Viewed 40

On our production server we got the following error when restarting django or try to run 'python manage.py makemigrations'

django.core.exceptions.FieldDoesNotExist: pricing.pricing has no field named 'price_per_hour'

What is strange is that the field price_per_hour was renamed long time ago to price and the migration when well.

But now I got this error every time and it is preventing to make any other model modification (in any app) and migrations.

What I checked :

  • If I run 'python manage.py showmigrations' every migration is flagged with an X, which if I'm right, means all the migration were done

  • price_per_hour is no longer find/used in any of the django app / class

class Pricing(models.Model):
    
    price = models.DecimalField(default=5,max_digits=10, decimal_places=2)
    
    class Meta: 
        ordering = ['-price',]  
                                           
    def __str__(self):
       return "{}".format(self.price)

  • I also exported the matching./current database in sql and we well see that it contains price column and not price_per_hour. And no reference anywhere to price_per_hour
CREATE TABLE public.pricing_pricing (
    id integer NOT NULL,
    price numeric(10,2) NOT NULL,
);
  • I also tried to rename the filed price to price_per_hour just in case but it didn't help

For me it seems the error comes from Django rather than the PostgreSQL database but I'm not sure.

Here is the complete traceback

python manage.py makemigrations
Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 369, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/core/management/commands/makemigrations.py", line 141, in handle
    loader.project_state(),
  File "/usr/local/lib/python3.8/site-packages/django/db/migrations/loader.py", line 324, in project_state
    return self.graph.make_state(nodes=nodes, at_end=at_end, real_apps=list(self.unmigrated_apps))
  File "/usr/local/lib/python3.8/site-packages/django/db/migrations/graph.py", line 315, in make_state
    project_state = self.nodes[node].mutate_state(project_state, preserve=False)
  File "/usr/local/lib/python3.8/site-packages/django/db/migrations/migration.py", line 87, in mutate_state
    operation.state_forwards(self.app_label, new_state)
  File "/usr/local/lib/python3.8/site-packages/django/db/migrations/operations/fields.py", line 326, in state_forwards
    raise FieldDoesNotExist(
django.core.exceptions.FieldDoesNotExist: pricing.pricing has no field named 'price_per_hour'

I don't know what other things to look for so, any idea or suggestion will be really appreciated

PS : I thought of removing all the migration files and re-running them but as this is a production server I'm afraid to lose the database content or break something.

find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc"  -delete
2 Answers

The error is found on the row migrations/operations/fields. Somehow a discrepancy between the database and the migrations files has occurred, or perhaps you applied a RunPython command in your migration file that references to this field.

I also faced a similar issues, and in my case it appeared to be a creation and deletion of a specific field in two old migration files that seemed to be the issue.

The solution for you is to 'fix' the old migration files, or squash your history.

Option 1) Fixing the error would require you to go through all migrations files and manually edit the migrations where this error stems from. If you can run the makemigration command in your local editor in debug mode you can track where this error occurs. Sadly Django's errorhanding on these errors are not that detailed.

Option 2) An easier option, the option which I would go for, is to squash the migration files. You thus remove all the history of the migration files, and reduce it to a single migration step. See docs. A downside is that you lose all your history, so make sure your local, staging and production environment is all synced up. Specifically on production, make sure that the database model (if you use postgres you can use pgadmin) is exactly the same as your Django model seen in the code.

Squashing the migration files actually removes the whole history. In your example, if you have a migration to add a field price_per_hour, and one to rename that field later to price, squashing will merge those migration files into a single action that makes the field price.

So what Boris described was the issue I had. There were incoherences in migration files and django couldn't make the migrations.

To be more precise in my case the error 'the pricing.pricing has no field named' was due to the fact that in the initial migration file the field was named price, but in the second migration file it was asked to rename price_per_hour (which didn't exist) to price and so the error

0001_initial.py

    migrations.CreateModel(
            name='Pricing',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('price', models.DecimalField(decimal_places=2, default=5, max_digits=10)),
0002_auto_20200304_1344.py

  operations = [
        migrations.RenameField(
            model_name='pricing',
            old_name='price_per_hour',
            new_name='price',
        ),

So both options described by Boris are those to follow. First you can try to go through all migrations files and hopefully find and fix manually the error. To find out which one caused trouble I did this https://stackoverflow.com/a/53135777/20025351

And if you cannot fix it manually (that was my case) I made sure to have the database model matching the Django models, then I removed all the migrations files and re-run migration/migrate.

Related