2010-06-24 6 views
3

Nous avons une application Django qui contient une liste d'articles de journaux. Chaque article a une relation m2m avec à la fois un «porte-parole», ainsi qu'une «entreprise» (entreprise mentionnée dans l'article).Django Admin - Affichage des champs intermédiaires pour les modèles M2M

Pour l'instant, la page Ajouter un article pour créer de nouveaux articles est assez proche de ce que nous voulons - c'est juste le stock Django Admin, et nous utilisons filter_horizontal pour définir les deux relations m2m.

L'étape suivante consistait à ajouter un champ "rating" comme champ intermédiaire sur chaque relation m2m.

Ainsi, un exemple de notre models.py

class Article(models.Model): 
    title = models.CharField(max_length=100) 
    publication_date = models.DateField() 
    entry_date = models.DateField(auto_now_add=True) 
    abstract = models.TextField() # Can we restrict this to 450 characters? 
    category = models.ForeignKey(Category) 
    subject = models.ForeignKey(Subject) 
    weekly_summary = models.BooleanField(help_text = 'Should this article be included in the weekly summary?') 
    source_publication = models.ForeignKey(Publication) 
    page_number = models.CharField(max_length=30) 
    article_softcopy = models.FileField(upload_to='article_scans', null=True, blank=True, help_text='Optionally upload a soft-copy (scan) of the article.') 
    url = models.URLField(null=True, blank=True, help_text = 'Enter a URL for the article. Include the protocl (e.g. http)') 
    firm = models.ManyToManyField(Firm, null=True, blank=True, through='FirmRating') 
    spokesperson = models.ManyToManyField(Spokeperson, null=True, blank=True, through='SpokespersonRating') 

    def __unicode__(self): 
     return self.title 

class Firm(models.Model): 
    name = models.CharField(max_length=50, unique=True) 
    homepage = models.URLField(verify_exists=False, help_text='Enter the homepage of the firm. Include the protocol (e.g. http)') 

    def __unicode__(self): 
     return self.name 

    class Meta: 
     ordering = ['name'] 

class Spokeperson(models.Model): 
    title = models.CharField(max_length=100) 
    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50) 

    def __unicode__(self): 
     return self.first_name + ' ' + self.last_name 

    class Meta: 
     ordering = ['last_name', 'first_name'] 

class FirmRating(models.Model): 
    firm = models.ForeignKey(Firm) 
    article = models.ForeignKey(Article) 
    rating = models.IntegerField() 

class SpokespersonRating(models.Model): 
    firm = models.ForeignKey(Spokesperson) 
    article = models.ForeignKey(Article) 
    rating = models.IntegerField() 

La question ici est qu'une fois que nous changeons notre entreprise et sur le terrain de Porte-parole « à » et des intermédiaires, notre page Ajouter article n'a plus filter_horizontal contrôle pour ajouter des relations Firms/Spokeperson à l'article - ils disparaissent complètement. Vous ne pouvez pas les voir du tout. Je n'ai aucune idée de pourquoi c'est. J'espérais qu'il y aurait un moyen de continuer à utiliser le widget cool_horizontal cool pour définir la relation, et en quelque sorte juste d'intégrer un autre champ ci-dessous pour le réglage de la cote. Cependant, je ne suis pas sûr de savoir comment faire cela tout en tirant parti de l'administrateur Django.

J'ai vu un writeup ici au sujet de la suppression d'un seul widget dans l'admin Django:

http://www.fictitiousnonsense.com/archives/22

Cependant, je ne sais pas si cette méthode est toujours valide, et je ne suis pas sûr de l'appliquer ici, avec un FK à un modèle intermédiaire (c'est fondamentalement un inline alors?).

Sûrement il y a un moyen facile de faire tout cela?

Cheers, Victor

Répondre

7

Le problème est que la méthode de l'administrateur formfield_for_manytomany dans django.contrib.admin.options ne retourne pas un champ de formulaire pour les champs ManyToMany avec un modèle intermédiaire! http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L157

Vous devrez remplacer cette méthode dans votre ModelAdmin:

def formfield_for_manytomany(self, db_field, request=None, **kwargs): 
    """ 
    Get a form Field for a ManyToManyField. 
    """ 
    # If it uses an intermediary model that isn't auto created, don't show 
    # a field in admin. 
    if not db_field.rel.through._meta.auto_created: 
     return None # return something suitable for your needs here! 
    db = kwargs.get('using') 

    if db_field.name in self.raw_id_fields: 
     kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, using=db) 
     kwargs['help_text'] = '' 
    elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): 
     kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) 
+0

Hmm, donc je dois remplacer cette méthode en quelque sorte, d'une manière généralisée qui ne casse rien? Urgh, ma connaissance de Django fait un peu défaut ici. Comment les gens modifient-ils normalement les modèles intermédiaires avec l'administrateur Django? – victorhooi

+0

Vous devez seulement le remplacer pour votre champ, vous pouvez mettre quelque chose comme 'if db_field.name == 'my_field' là! –

Questions connexes