Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django migration: making a row not primary key, getting "ProgrammingError: multiple default values"?

I am working with Postgres on a Django app and I want to make a model change, resetting a row so it is no longer the primary key.

This is what my model currently looks like in Django:

class Meeting(TimeStampedModel):
    row = models.CharField(max_length=20, primary_key=True)
    total_items = models.IntegerField()

I have run django-admin.py flush to remove all data from the database. If I run python manage.py makemigrations I see No changes detected. So we are starting from a clean base.

Now I edit row in models.py so it is no longer the primary key:

row = models.CharField(max_length=20)

And run python manage.py makemigrations and set 1 as the default when asked:

You are trying to add a non-nullable field 'id' to meeting without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
>>> 1
Migrations for 'frontend':
  0007_auto_20150305_1129.py:
    - Add field id to meeting
    - Alter field row on meeting

That seems to run OK. Then if I run python manage.py migrate:

$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: debug_toolbar
  Apply all migrations: contenttypes, frontend, sites, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying frontend.0007_auto_20150305_1129...Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/me/.virtualenvs/meetings/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  ...
  File "/Users/me/.virtualenvs/meetings/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: multiple default values specified for column "id" of table "frontend_meeting"

Why is it telling me I have multiple default values?

Do I need to set a unique primary key value as a default - and if so, how can I do this?

This is what the migrations file looks like:

class Migration(migrations.Migration):

    dependencies = [
        ('frontend', '0006_auto_20150305_1050'),
    ]

    operations = [
        migrations.AddField(
            model_name='meeting',
            name='id',
            field=models.AutoField(auto_created=True, primary_key=True, default=1, serialize=False, verbose_name='ID'),
            preserve_default=False,
        ),
        migrations.AlterField(
            model_name='meeting',
            name='row',
            field=models.CharField(max_length=20),
            preserve_default=True,
        ),
    ]
like image 730
Richard Avatar asked Mar 05 '15 11:03

Richard


People also ask

How do I fix migration issues in Django?

1. Run makemigrations to verify if your schema and your database are identical, but if our local initial migration is differs from the one that was applied to the database , Django won't let us know of this, and it'll say that is all good, but because of that, the local differences that you have won't be applied. 2.

Should I ignore migrations in Django?

There is only one file in migration folder that you should not ignore. That file is init.py file, If you ignore it, python will no longer look for submodules inside the directory, so any attempts to import the modules will fail.

What does fake migration do in Django?

--fake-initialAllows Django to skip an app's initial migration if all database tables with the names of all models created by all CreateModel operations in that migration already exist. This option is intended for use when first running migrations against a database that preexisted the use of migrations.


1 Answers

Try to use an intermediate migration to achieve this:

1) Add id = models.IntegerField() to your model. Run makemigrations and then migrate.

2) Remove primary_key=True from the 'row'-field, and also remove the 'id'-field. Again run makemigrations and migrate.

like image 112
Mika Avatar answered Nov 08 '22 02:11

Mika