如何在Django Admin中动态访问外键字段

时间:2013-06-12 14:54:01

标签: python django django-models django-admin getattr

所以我有这样的模特:

class Celebrity(models.Model):
    #30+ fields here ...

class HoneyBadger(models.Model):
    name = models.CharField(max_length=10)
    celebrity_owner = models.ForeignKey(Celebrity)

现在我希望HoneyBadger的管理界面显示该生物的名称以及名人所有者字段。

我知道标准建议是做这样的事情:

class HoneyBadger(models.Model):
    name = models.CharField(max_length=10)
    celebrity_owner = models.ForeignKey(Celebrity)

    def owner_birth_date(self):
        return self.celebrity_owner.birth_date
    #And so on for every other field in celebrity_owner

然后在管理员中引用这些方法。

相反,我想要一种方法来保存自己所有输入的内容!

这是我第一次尝试懒惰的捷径:

class HoneyBadger(models.Model):
    name = models.CharField(max_length=10)
    celebrity_owner = models.ForeignKey(Celebrity)

    def __getattr__(self, name):
        """Dynamically make derived fields for celebrity_owner fields so I don't have to type out"""
        field_lookup_prefix = 'celebrity_owner_field_'
        if name.startswith(field_lookup_prefix):
            field_name = name[len(field_lookup_prefix):]
            def wrapper(*args, **kwargs):
                return getattr(self.celebrity_owner, field_name)
            return wrapper
        else:
            raise AttributeError('%s not found' % name)

当我在shell中运行它时,它确实有效,但Django管理员并不喜欢它。我收到这个错误:

ImproperlyConfigured at /admin/tracker/

HoneyBadgerAdmin.list_display[5], 'celebrity_owner_field_birth_date' is not a callable or an attribute of 'HoneyBadgerAdmin' or found in the model 'HoneyBadger'.

有谁知道如何让我的代码与管理员一起工作,或者是否有另一种方法可以为每个名人字段输入一个方法? (也许某种运行时猴子修补?)

2 个答案:

答案 0 :(得分:2)

有两种可行的解决方法可以实现您的目标。

  1. 在HoneyBadger管理员中提供指向Celebrity对象的链接:

    def celebrity_link(self):
        return '<a href="%s">%s</a>' % (reverse('admin:appname_celebrity_change',args=(self.celebrity_owner.id,)), self.celebrity_owner.celeb_name)
    
    celebrity_link.allow_tags = True
    celebrity_link.short_description = u'Celebrity'
    
    class HoneyBadgerAdmin(admin.ModelAdmin):
        list_display = [..., celebrity_link, ...]
    
  2. 下一个解决方案有点复杂,但我们会完全按照自己的意愿行事:定义自定义管理模板。基本上从django源复制更改表单并添加自定义代码以显示名人信息。请参阅此documentation

答案 1 :(得分:1)

看起来您想要使用名称字段扩展名人类?为什么不在HoneyBadger类中继承该类?

class HoneyBadger(Celebrity):
    name = models.CharField(max_length=10)

(您可能必须先从数据库中删除旧的HoneyBadger表才能使其正常工作。)