2009-07-13 6 views
3

Je veux modéliser un article avec des révisions de Django:Comment modéliser une façon unique à une relation dans Django

Je suit dans models.py de mon article:

class Article(models.Model): 
    title = models.CharField(blank=False, max_length=80) 
    slug = models.SlugField(max_length=80) 

    def __unicode__(self): 
     return self.title 

class ArticleRevision(models.Model): 
    article = models.ForeignKey(Article) 
    revision_nr = models.PositiveSmallIntegerField(blank=True, null=True) 
    body = models.TextField(blank=False) 

Sur la modèle artlcle Je veux avoir 2 références directes à une révision - une référence à une révision publiée et une autre à une révision en cours d'édition. Cependant, d'après ce que je comprends, les références OneToOne et ForeignKey génèrent une référence arrière de l'autre côté de la référence du modèle, donc ma question est, comment puis-je créer une référence unidirectionnelle one-to-one dans Django?

Y at-il une incantation spéciale pour cela ou dois-je simuler en incluant l'état dans la révision et les implémentations personnalisées des champs qui demandent une révision dans un état spécifique?

Editer: Je suppose que j'ai fait un travail assez médiocre pour expliquer mon intention. Essayons à un niveau d'abstraction supérieur:

Mon intention initiale était de mettre en œuvre une sorte de modèle d'article révisé, où chaque article peut avoir plusieurs révisions, où une de ces révisions peut être "publiée" et une révisée activement.

Cela signifie que l'article aura un à-plusieurs à des révisions (représentés par ForeignKey(Article) référence dans ArticleRevision classe) et deux références d'une façon de l'article à la révision: published_revision et .

Ma question est principalement comment puis-je modéliser cela avec l'ORM de Django?

+0

Pas vraiment une réponse, mais il existe déjà quelques solutions pour la gestion des versions des modèles Django, par ex. django-reversion (http://code.google.com/p/django-reversion) ou AuditTrail (http://code.djangoproject.com/wiki/AuditTrail).Peut-être que l'un d'entre eux correspond à vos besoins et vous n'avez pas besoin de réinventer la roue :-) –

+0

Je ne veux pas de versionnage automatique de mes modèles (c'est ce que font ces deux modèles). Ce que je cherche, c'est plus d'une révision "manuelle", où une révision d'article est un article jusqu'à ce qu'il soit publié. Toute modification apportée à un article publié crée une nouvelle révision. La publication de la nouvelle révision verrouillera cette révision et la configurera comme révision publiée et l'édition suivante sur l'article répétera le cycle d'édition-publication (je crois personnellement que c'est beaucoup plus gérable pour les utilisateurs réguliers que "chaque édition est une révision "approche". –

Répondre

4

Les références arrière que Django produit sont programmatiques et n'affectent pas le schéma de base de données sous-jacent. En d'autres termes, si vous avez un champ de clé un-à-un ou étranger sur votre article pointant vers votre Révision, une colonne sera ajoutée à la table Article dans la base de données, mais pas à la table Révision.

Ainsi, supprimer la relation inverse de la révision à l'article n'est pas nécessaire. Si vous y tenez vraiment, et que vous voulez documenter dans votre code que le backlink n'est jamais utilisé, un idiome Django assez commun est de donner aux champs un attribut related_name comme _unused_1. Ainsi, le modèle de votre article pourrait ressembler à ce qui suit:

class Article(models.Model): 
    title = models.CharField(blank=False, max_length=80) 
    slug = models.SlugField(max_length=80) 
    revision_1 = models.OneToOneField(ArticleRevision, related_name='_unused_1') 
    revision_2 = models.OneToOneField(ArticleRevision, related_name='_unused_2') 

    def __unicode__(self): 
     return self.title 

Cela dit, il est rare qu'un être à une relation est réellement utile dans une application (à moins que vous optimisez pour une raison quelconque) et je suggère de revoir attentivement votre schéma de base de données pour vous assurer que c'est vraiment ce que vous voulez. Il peut être judicieux de garder un seul champ ForeignKey sur votre ArticleRevision pointant vers un Article (puisqu'une ArticleRevision devra, sans doute, toujours être associée à un Article) et d'ajouter une autre colonne à la Révision indiquant si elle est publiée.

+0

La relation un-à-un est utile, mais dans mon cas, la référence arrière doit déjà exister sous la forme d'une référence article-révisions et les références supplémentaires servent uniquement à marquer les références directes à la révision actuellement publiée. –

+1

Depuis Django 1.2, related_name = '+' n'entrainera aucune relation en arrière disponible. https://docs.djangoproject.com/fr/1.2/ref/models/fields/#django.db.models.ForeignKey.related_name – tobych

4

Quel est le problème avec le lien allant dans les deux sens? Je pense que le OneToOneField serait le choix parfait ici. Y a-t-il une raison particulière pour laquelle cela nuirait à votre demande? Si vous n'avez pas besoin de la référence arrière, pourquoi ne pouvez-vous pas l'ignorer?

+2

Un argument related_name résoudra tout problème avec les tables si vous devez pointer vers deux modèles différents d'ArticleRevision. Ce serait ma réponse. – AlbertoPL

Questions connexes