Django管理界面 - 显示M2M模型的中间字段

4
我们有一个Django应用程序,其中包含一系列报纸文章。每篇文章都与“发言人”和“公司”(在文章中提到的公司)具有m2m关系。
目前,创建新文章的添加文章页面非常接近我们想要的内容-它只是标准的Django管理页面,并且我们正在使用filter_horizontal设置这两个m2m关系。
下一步是在每个m2m关系上添加“评分”字段作为中介字段。
因此,我们的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()

问题在于,一旦我们将公司和发言人字段更改为“通过”并使用中介,我们的添加文章页面就不再具有filter_horizontal控件来添加公司/发言人与文章的关系 - 它们完全消失了。您根本看不到它们。我不知道为什么会这样。
我希望能找到一种方法继续使用酷炫的filter_horizontal小部件来设置关系,并在其下嵌入另一个字段以设置评级。但是,我不确定如何在仍然利用Django管理界面的情况下实现这一点。
我在这里看到了一篇关于重写Django管理界面单个小部件的文章:

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

然而,我不确定那种方法是否仍然有效,也不确定将其应用于此处,带有一个FK到一个中间模型(基本上是一个内联?)。
肯定有一种简单的方法来完成所有这些吧?
谢谢, 维克托
1个回答

8
问题在于Django的django.contrib.admin.options模块中,管理员方法formfield_for_manytomany无法为具有中间模型的多对多字段返回表单字段。您需要在ModelAdmin中覆盖此方法。 http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L157

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))

嗯,所以我需要以一种通用的方式覆盖这个方法,而不会破坏任何东西?唉,我的Django知识在这里有点欠缺。人们通常如何使用Django管理编辑中介模型? - victorhooi
你只需要为你的字段覆盖它,你可以在那里放置类似 if db_field.name == 'my_field' 的内容! - Bernhard Vallant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接