39

This is from django's documentation:

Field.unique

If True, this field must be unique throughout the table.

This is enforced at the database level and by model validation. If you try to save a model with a duplicate value in a unique field, a django .db.IntegrityError will be raised by the model’s save() method.

Here is my models.py

class MyModel(models.Model):
    # my pk is an auto-incrementing field
    url = models.URLField("URL", unique=True)
    text = models.TextField(max_length=1000)
    # my model is just two fields, one pk (unique), and another unique field, 
    #, the url

Here my is manage.py sqlall (I ran syncdb)

CREATE TABLE `MyModel_mymodel` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
     `url` varchar(200) NOT NULL UNIQUE,
     `text` varchar(1000) NOT NULL,

However, in the manage.py shell, I can freely do this:

>>> from MyModel.models import MyModel
>>> MyModel().save() # it works fine!? Not even the text was checked for!
>>> MyModel(url="blah").save() 
>>> MyModel(url="blah").save() # it still works!

# I checked the mysql database afterwards, the models were saved just fine, they
# however did have different PK's (auto incrementing fields).

I'm using mysql, django 1.5. Does anyone have an idea what could possible be causing this?

I am using a custom manager, but I doubt that's the issue.

Thanks.

3
  • 1
    I got IntegrityError: column url is not unique exception for the second MyModel(url="blah").save(). Did you paste your code as is?
    – falsetru
    Commented Jul 13, 2013 at 6:25
  • 1
    text field definition has typo.. modes. I suspect you did not copy&paste your code as is.
    – falsetru
    Commented Jul 13, 2013 at 6:26
  • No I did not, don't think the code needs to be posted as is, only two fields are notable Commented Jul 13, 2013 at 6:28

3 Answers 3

49

For django 1.9+
Running makemigrations then migrate applies the unique constraint to sqlite3

For django < 1.9
Since you are using django 1.5, this solution will apply.

If you added the unique=True after the table was already created, then even if you do syncdb later, the unique condition will not be added to your table.

I can confirm with sqlite3 that Django 1.5 happily saves duplicate objects with MyModel(url="blah").save() if the unique constraint does not exist in the database, which seems to contradict with the docs.

The best solution for you is to create the constraint manually in your database using this command.

ALTER TABLE MyModel_mymodel ADD UNIQUE (url);

Or if you don't mind, you can recreate your table. (Drop the table and then run syncdb.)

4
  • Thank you, it works. I wish django was easier on a lot of this db stuff, like changing & removing FK's, etc. Commented Jul 13, 2013 at 6:39
  • 3
    With django 1.9.4 the unique condition is added to the table (with sqlite3) - even if the table was already created.
    – Mike Vella
    Commented Apr 12, 2016 at 23:50
  • Django 1.8 and mysql does not create unique entries if you add unique=True to your model field after table creation. An overview of the Django Version together with the database regarding unique=working would be helpful?!
    – Timo
    Commented Jun 1, 2017 at 7:32
  • I was confused too. The thing to note is that model validation, which occurs in the admin interface, does not occur during save(). Instead, uniqueness during save is enforced only at the database level. Commented Mar 24, 2020 at 20:31
1

Running sql scripts directly on the db can be avoided. Rather add the sql execution in your migration:

from __future__ import unicode_literals
from django.db import migrations, connection


def alter_table(apps, schema_editor):
    query ="ALTER TABLE <your table> ADD UNIQUE (unique_col);"
    cursor = connection.cursor()
    cursor.execute(query)
    cursor.close()

class Migration(migrations.Migration):

    dependencies = [
        ('app', 'yourlastmigration'),
    ]

    operations = [        
        migrations.RunPython(alter_table),
    ]
0

The solution is pretty simple, Just follow their steps.

1 - Dell all the files in the migration folder
2 - Then run the command "python manage.py makemigrations"
3 - Then run the command "python manage.py migrate"

OR

Do it by the help of a simple SQL-lite Query Adding index Example

alter table test add index index_name(col1(255),col2(255));

Adding unique index Example

alter table test add unique index_name(col1(255),col2(255));

2
  • If I delete all the fields then how to get my previous data?
    – Shamim
    Commented Dec 11, 2019 at 8:43
  • @Shamim your data is in the _sql database or another database not in the migration folder, so ur data is safe. Commented Dec 11, 2019 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.