how to update model in django by adding new primary key field?

9.5k Views Asked by At

How to replace default primary key in Django model with custom primary key field?

I have a model with no primary key defined at first since django automatically adds an id field by default as primary field.

#models.py
from django.db import models

class Event(models.Model):
    title = models.CharField(max_length=50, unique=True)
    description = models.CharField(max_length=150)

I added some objects into it from django shell.

>>e = Event('meeting', 'Contents about meeting')
>>e.save()
>>e = Event('party', 'Contents about party')
>>e.save()

Then I require to add custom character field as primary into this model.

class Event(models.Model):
    event-id = models.CharField(max_length=50, primary_key=True)
    ...

Running makemigrations:

$ python manage.py makemigrations
You are trying to add a non-nullable field 'event-id' to event 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()
>>> 'meetings'
Migrations for 'blog':
  0002_auto_20141201_0301.py:
    - Remove field id from event
    - Add field event-id to event

But while running migrate it threw an error:

.virtualenvs/env/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 485, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: UNIQUE constraint failed: blog_event__new.event-id
3

There are 3 best solutions below

0
On

Django has already established an auto incrementing integer id as primary key in your backend as and when u made the previous model.

When u were trying to run the new model , An attempt was made to recreate a new primary key column that failed.

Another reason is,When u made the field,Django was expecting a unique value be explicitly defined for each new row which it couldn't found,hence the reason.

As told in previous answer you can re-create the migration and then try doing it again.It should work.. cheers :-)

1
On

The problem is that you made the field unique, then attempted to use the same value for all the rows in the table. I'm not sure if there's a way to programmatically provide the key, but you could do the following:

  • Delete the migration
  • Remove the primary_key attribute from the field
  • Make a new migration
  • Apply it
  • Fill in the value for all your rows
  • Add the primary_key attribute to the field
  • Make a new migration
  • Apply it

It's bruteforce-ish, but should work well enough.

Best of luck!

0
On

In my experience (using Django 1.8.* here), I've seen similar situations when trying to update the PK field for models that already exist, have a Foreign Key relationship to another model, and have associated data in the back-end table.

You didn't specify if this model is being used in a FK relation, but it seems this is the case.

In this case, the error message you're getting is because the data that already exists needs to be made consistent with the changes you're requesting --i.e. a new field will be the PK. This implies that the current PK must be dropped for django to 'replace' them. (Django only supports a single PK field per model, as per docs[1].)

Providing a default value that matches currently existing data in the related table should work.

For example:

class Organization(models.Model):
    # assume former PK field no longer here; name is the new PK
    name = models.CharField(primary_key=True)

class Product(models.Model):
    name = models.CharField(primary_key=True)
    organization = models.ForeignKey(Organization)

If you're updating the Organization model and products already exist, then existing product rows must be updated to refer to a valid Organization PK value. During the migration, you'd want to choose one of the existing Organization PKs (e.g. 'R&D') to update the existing products.

[1] https://docs.djangoproject.com/en/1.8/topics/db/models/#automatic-primary-key-fields