9
votes

Erreur lors de l'utilisation d'un champ de classe de base dans la sous-classe unique_toGether Meta Option

Utilisation du code suivant: XXX PRE>

Essayer de SyncDB Donnez-moi cette erreur: P>

Error: One or more models did not validate:
organizations.division: "unique_together" refers to alias. This is not in the 
same model as the unique_together statement.


2 commentaires

Pouvez-vous expliquer davantage l'exigence, incapable de comprendre quelle est la nécessité d'hériter d'une organisation et d'avoir une entreprise d'essence au même modèle de base.


C'est une simple relation parent-enfant une organisation peut avoir plusieurs divisions, une division est une sorte une organisation spécialisée.


5 Réponses :


15
votes

Ceci est par conception. Lire la documentation pour le option unique_together , il étage que:

Il est utilisé dans l'administrateur Django et est appliqué au niveau de la base de données .

Si vous regardez la table qu'une sous-classe crée, vous verrez que cela ne réellement a les champs que son parent a. Au lieu de cela, il obtient une clé étrangère molle à la table des parents avec un nom de champ appelé [champ] _ptr_id , où [champ] est le nom de la table que vous hériter d'exclure le nom de l'application. Donc, votre table de division a une clé étrangère primaire appelée organisation_ptr_id .

Maintenant parce que unique_together est appliqué au niveau de la base de données à l'aide de la contrainte unique , il n'y a aucun moyen que je connaisse pour la base de données pour appliquer réellement cela à un champ non dans la table.

Votre meilleur pari est probablement via validateurs à votre entreprise-logique niveau ou repensez votre schéma de base de données pour prendre en charge la contrainte.

Edit: Comme MANOJ a souligné, vous pouvez également essayer d'utiliser validateurs de modèle tels que validate_unique .


1 commentaires

+1 pour mentionner pourquoi et relier les validateurs. Vous voudrez peut-être signaler Validations de modèle aussi. Par exemple, validate_unique : docs.djangoproject.com/fr/dev/ref/models/instances/...



3
votes

[modèle] Les validateurs fonctionneraient pour vous. Peut-être plus simple, cependant, serait d'utiliser: xxx

Remarque: comme avec votre code actuel, vous ne pouvez pas avoir de subdivisions des divisions.


0 commentaires

2
votes

C'est une solution que j'ai récemment utilisée à Django 1.6 (grâce à Manoj Govindan pour l'idée):

class Organization(models.Model):
    name = models.CharField(max_length="100",)
    alias = models.SlugField()
    ...

class Division(Organization):
    parent_org = models.ForeignKey(Organization)

    # override Model.validate_unique
    def validate_unique(self, exclude=None):     
        # these next 5 lines are directly from the Model.validate_unique source code
        unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
        errors = self._perform_unique_checks(unique_checks)
        date_errors = self._perform_date_checks(date_checks)
        for k, v in date_errors.items():
            errors.setdefault(k, []).extend(v)

        # here I get a list of all pairs of parent_org, alias from the database (returned 
        # as a list of tuples) & check for a match, in which case you add a non-field 
        # error to the error list
        pairs = Division.objects.exclude(pk=self.pk).values_list('parent_org', 'alias')
        if (self.parent_org, self.alias) in pairs:
                errors.setdefault(NON_FIELD_ERRORS, []).append('parent_org and alias must be unique')

        # finally you raise the ValidationError that includes all validation errors, 
        # including your new unique constraint
        if errors:
            raise ValidationError(errors)


1 commentaires

Évidemment, cela n'implique aucun contrôle de niveau de base de données, car une contrainte unique dans une table serait, mais en termes de validation de Django, cette solution a fonctionné de manière transparente pour moi. Celui que je devais corriger était de m'assurer d'exclure l'instance appelant validate_unique (donc exclure (pk = self.pk)).



2
votes

Cela n'applique pas strictement la question mais est très étroitement lié; unique_together fonctionnera si la classe de base est abstraite. Vous pouvez marquer des classes de modèle abstraites comme telles utilisez: xxx

Cela empêchera Django de créer une table pour la classe et ses champs seront directement inclus dans toutes les sous-classes. Dans cette situation, unique_together est possible car tous les champs sont dans la même table.

https://docs.djangoproject.com/fr/1.5/topics/db/models/#AbRact-Base-classes


0 commentaires

0
votes

J'ai eu un défi similaire pour essayer d'appliquer unique_together à un groupe d'autorisations créé par un client donné.

class ClientGroup(Group):
    client = models.ForeignKey(Client, on_delete=models.CASCADE)
    is_active = models.BooleanField()

    class Meta():
        # looking at the db i found a field called group_ptr_id.
        # adding group_ptr did solve the problem.
        unique_together = ('group_ptr', 'client', 'is_active')


0 commentaires