Django Admin - Visualizzazione Intermediario I campi per i modelli M2M
Domanda
Abbiamo un app Django che contiene un elenco di articoli di giornale. Ogni articolo ha un rapporto M2M sia con un "portavoce", così come un "fermo" (società menzionata nell'articolo).
Al momento, la pagina articolo Aggiungi per la creazione di nuovi articoli è abbastanza vicino a quello che vogliamo -. È solo il titolo Django Admin, e stiamo usando filter_horizontal per l'impostazione dei due rapporti M2M
Il passo successivo è stato quello di aggiungere un campo "rating" come un campo di intermediario su ogni rapporto m2m.
Quindi, un esempio del nostro 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()
Il problema qui è che una volta che cambiamo la nostra Azienda e il campo Portavoce a "attraverso" e gli intermediari di utilizzo, la nostra pagina Add articolo non ha un controllo filter_horizontal per aggiungere Aziende / rapporti portavoce per l'articolo - che scompaiono completamente. Non è possibile vedere affatto. Non ho idea perché questo è.
speravo per lì per essere un modo per continuare a utilizzare il fresco filter_horizontal widget per impostare il rapporto, e in qualche modo solo incorporare un altro campo di sotto di quella per impostare il rating. Tuttavia, non sono sicuro di come fare questo mentre ancora potendo contare su l'amministratore Django.
ho visto un interessante resoconto qui circa l'override un unico widget nella Django admin:
http://www.fictitiousnonsense.com/archives/22
Tuttavia, non sono sicuro se questo metodo è ancora valido, e io non sono sicuro di applicarlo a qui, con un FK a un modello intermedio (è fondamentalmente un inline allora?).
Sicuramente c'è un modo facile di fare tutto questo?
Saluti, Victor
Soluzione
Il problema è che il metodo formfield_for_manytomany
del admin in django.contrib.admin.options
non restituisce un campo di modulo per i campi ManyToMany con un modello di intermediazione! http://code.djangoproject.com/browser /django/trunk/django/contrib/admin/options.py#L157
Si dovrebbe ignorare questo metodo nella 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))