2016-11-27 1 views
1

Je possède ce modèle:enregistrements en double lorsque treeforeignkey est nulle dans django MPTT

class Genre(MPTTModel): 
    id = models.CharField(max_length=100) 
    name = models.CharField(max_length=100) 
    parent = TreeForeignKey(
     'self', 
     null=True, 
     blank=True, 
     related_name='subgenre' 
    ) 

    def __str__(self): 
     return self.name 

    class Meta: 
     unique_together = (('id', 'parent'),) 

Je ne voulais pas avoir des doublons, donc je suis en utilisant unique_together avec l'identifiant et le TreeForeignKey.

Même avec unique_together, je suis toujours capable d'ajouter des doublons lorsque je mets le parent à null. Comment puis-je éviter cela?

Répondre

0

Il s'agit d'une décision de conception SQL.

SQL 2011 draft, à la page 474 se lit comme suit:

S'il n'y a pas deux lignes de T de telle sorte que la valeur de chaque colonne dans une rangée est non-nulle et ne se distingue pas de la valeur de la colonne correspondante dans l'autre rangée, le résultat est True; sinon, le résultat de la est False.

Cela signifie que deux valeurs NULL sont considérées comme distinctes lorsqu'il s'agit de la contrainte unique. Ceci contredit la définition du type de données NULL à la page 41:

Deux valeurs nulles ne sont pas distinctes.

Une valeur nulle et une valeur non nulle sont distinctes.

Deux valeurs non nulles sont distinctes si les règles générales du sous-paragraphe 8.15, «», renvoient Vrai.

Règles générales de 8.15 dit Le paragraphe:

Si les deux V1 et V2 sont la valeur nulle, alors le résultat est faux.

Pour résumer:

En ce qui concerne le type de données, le "caractère distinctif" des deux est nulls sens Faux NULL == NULL.

Mais la contrainte unique au niveau de la table indique autrement: NULL! = NULL. Il peut y avoir plusieurs valeurs NULL dans un champ d'une table qui indique qu'elles doivent être uniques.

Le suivi de ticket Django est #1751 unique_together does not work when any of the listed fields contains a FK. La solution de contournement consiste à définir votre propre méthode de modèle .validate_unique comme mentionné dans le documentation. Le select_for_update crée un verrou pour éviter une condition de concurrence.

Cette solution fonctionne pour les soumissions de formulaire, elle ne fonctionne pas lors de l'accès direct à la méthode Genre.objects.create(). Dans cette situation, vous devez créer l'instance Genre en trois étapes:

genre = Genre(id='id1') 
genre.validate_unique() 
genre.save()