web-dev-qa-db-fra.com

Django unique = True ne fonctionne pas

Ceci est tiré de la documentation de Django:

Field.unique

Si True, ce champ doit être unique dans toute la table.

Ceci est appliqué au niveau de la base de données et par validation du modèle. Si vous essayez de sauvegarder un modèle avec une valeur dupliquée dans un champ unique, un Django .db.IntegrityError sera généré par la méthode save () du modèle.

Voici mes modèles.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

Voici mon manage.py sqlall (j'ai couru syncdb)

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

Cependant, dans le shell manage.py, je peux le faire librement:

>>> 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).

J'utilise mysql, Django 1.5. Est-ce que quelqu'un a une idée de ce qui pourrait être la cause?

J'utilise un gestionnaire personnalisé, mais je doute que ce soit le problème.

Merci.

29
Lucas Ou-Yang

Pour Django 1.9+
Lancer makemigrations puis migrate applique la contrainte unique à sqlite3.

Pour Django <1.9
Puisque vous utilisez Django 1.5, cette solution s’appliquera.

Si vous avez ajouté le unique=True après la création de la table, même si vous faites syncdb plus tard, la condition unique ne sera pas ajoutée à votre table.

Je peux confirmer avec sqlite3 que Django 1.5 enregistre volontiers les objets en double avec MyModel(url="blah").save() si la contrainte unique n'existe pas dans la base de données, ce qui semble contredire les documents.

La meilleure solution pour vous consiste à créer manuellement la contrainte dans votre base de données à l'aide de cette commande. 

ALTER TABLE MyModel_mymodel ADD UNIQUE (url);

Ou si cela ne vous dérange pas, vous pouvez recréer votre table. (Supprimez la table, puis exécutez syncdb.)

39
janos

L'exécution de scripts SQL directement sur la base de données peut être évitée. Ajoutez plutôt l'exécution SQL dans votre 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
Fred Campos