Voici mon modèle:
class GroupedModels(models.Model):
other_model_one = models.ForeignKey('app.other_model')
other_model_two = models.ForeignKey('app.other_model')
Essentiellement, ce que je veux, c'est other_model
être unique dans ce tableau. Cela signifie que s'il y a un enregistrement où se trouve other_model_one
id 123
, je ne dois pas autoriser la création d'un autre enregistrement avec other_model_two
id as 123
. Je peux remplacer, clean
je suppose, mais je me demandais si Django avait quelque chose de intégré.
J'utilise la version 2.2.5 avec PSQL.
Edit: Ce n'est pas une situation unqiue ensemble. Si j'ajoute un enregistrement avec other_model_one_id=1
et autre other_model_two_id=2
, je ne devrais pas pouvoir ajouter un autre enregistrement avec other_model_one_id=2
et autreother_model_two_id=1
python
django
django-models
Pittfall
la source
la source
Réponses:
J'explique plusieurs options ici, peut-être que l'une d'entre elles ou une combinaison peut vous être utile.
Primordial
save
Votre contrainte est une règle métier, vous pouvez remplacer la
save
méthode pour garder les données cohérentes:Changer la conception
Je mets un échantillon facile à comprendre. Supposons ce scénario:
Maintenant, vous voulez éviter qu'une équipe ne joue un match avec elle-même, l'équipe A ne peut jouer avec l'équipe B qu'une seule fois (presque vos règles). Vous pouvez repenser vos modèles comme:
ManyToManyField.symmetrical
Cela ressemble à un problème symétrique , Django peut le gérer pour vous. Au lieu de créer un
GroupedModels
modèle, créez simplement un champ ManyToManyField avec lui-même surOtherModel
:C'est ce que django a intégré à ces scénarios.
la source
match_id
sur la contrainte unike, pour permettre aux équipes de jouer des matchs illimités. Supprimez simplement ce champ pour restreindre à nouveau la lecture.Ce n'est pas une réponse très satisfaisante, mais malheureusement la vérité est qu'il n'y a aucun moyen de faire ce que vous décrivez avec une simple fonctionnalité intégrée.
Ce que vous avez décrit
clean
fonctionnerait, mais vous devez faire attention à l'appeler manuellement car je pense qu'il n'est appelé automatiquement que lorsque vous utilisez ModelForm. Vous pourriez être en mesure de créer une contrainte de base de données complexe mais qui vivrait en dehors de Django et vous auriez à gérer les exceptions de base de données (ce qui peut être difficile dans Django au milieu d'une transaction).Peut-être existe-t-il une meilleure façon de structurer les données?
la source
Il y a déjà une excellente réponse de la part de dani herrera , mais je souhaite en dire plus.
Comme expliqué dans la deuxième option, la solution requise par l'OP consiste à modifier la conception et à mettre en œuvre deux contraintes uniques par paire. L'analogie avec les matchs de basket-ball illustre le problème d'une manière très pratique.
Au lieu d'un match de basket, j'utilise l'exemple avec des matchs de football (ou de football). Un match de football (que j'appelle cela
Event
) est joué par deux équipes (dans mes modèles, une équipe estCompetitor
). Il s'agit d'une relation plusieurs-à-plusieurs (m:n
),n
limitée à deux dans ce cas particulier, le principe convient à un nombre illimité.Voici à quoi ressemblent nos modèles:
Un événement pourrait être:
Maintenant, nous devons résoudre le problème à partir de la question. Django crée automatiquement une table intermédiaire entre les modèles avec une relation plusieurs-à-plusieurs, mais nous pouvons utiliser un modèle personnalisé et ajouter d'autres champs. J'appelle ce modèle
Participant
:Le
ManyToManyField
possède une optionthrough
qui nous permet de spécifier le modèle intermédiaire. Changeons cela dans le modèleEvent
:Les contraintes uniques limiteront désormais automatiquement le nombre de concurrents par événement à deux (car il n'y a que deux rôles: Domicile et visiteur ).
Dans un événement particulier (match de football), il ne peut y avoir qu'une seule équipe à domicile et une seule équipe de visiteurs. Un club (
Competitor
) peut apparaître comme équipe à domicile ou comme équipe de visiteurs.Comment gérons-nous maintenant toutes ces choses dans l'administrateur? Comme ça:
Nous avons ajouté le
Participant
as inline dans leEventAdmin
. Lorsque nous créons de nouveaux,Event
nous pouvons choisir l'équipe d'accueil et l'équipe de visiteurs. L'optionmax_num
limite le nombre d'entrées à 2, donc pas plus de 2 équipes peuvent être ajoutées par événement.Cela peut être refactorisé pour différents cas d'utilisation. Disons que nos événements sont des compétitions de natation et au lieu de la maison et du visiteur, nous avons les couloirs 1 à 8. Nous refactorisons simplement
Participant
:Avec cette modification, nous pouvons avoir cet événement:
titre: FINA 2019, finale du 50 m dos hommes,
participants:
// et ainsi de suite voie 5 à voie 8 (source: Wikipedia
Un nageur ne peut apparaître qu'une seule fois dans une manche et un couloir ne peut être occupé qu'une seule fois dans une manche.
J'ai mis le code sur GitHub: https://github.com/cezar77/competition .
Encore une fois, tous les crédits reviennent à dani herrera. J'espère que cette réponse apporte une valeur ajoutée aux lecteurs.
la source