【问题标题】:How to Dynamically Access Fields from Foreign Key in Django Admin如何在 Django Admin 中从外键动态访问字段
【发布时间】:2013-06-08 18:02:49
【问题描述】:

所以我有这样的模型:

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'.

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

【问题讨论】:

  • 如果只是显示那些字段可以使用__unicode__()方法

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


【解决方案1】:

有两种可能的解决方法可以实现您想要的。

  1. 在 HoneyBadger Admin 中提供指向 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

【讨论】:

  • 我试过了。我不认为内联适用于外键,只适用于多对多。 (也许也适用于 1to1?)
  • @Greg 是的,我意识到此解决方案将不起作用,因为内联旨在向后跟踪关系。因此,如果您与提供的解决方案完全相反;即制作 HoneyBadgerInline 和 CelebrityAdmin,然后您可以让所有链接的 HoneyBadgers 显示在 Celebrity 管理页面中。但这正是我们想要的。最好的替代方法是提供指向 Celebrity 对象的链接。我将编辑解决方案以显示这一点。
【解决方案2】:

您似乎想使用名称字段扩展 Celebrity 类?为什么不在 HoneyBadger 类中继承该类?

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

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

【讨论】:

  • 继承不会使隐含的onetoone字段链接两者吗?一位名人可以拥有许多獾,所以这是行不通的。
  • 不,继承会将父类中的所有字段复制到子类中,因此 HoneyBadger 将在其表中包含所有 Celebrity 字段。这称为“is-a”关系,其中 HoneyBadger 是 Celebrity。
  • 如果您想要一个“has-a”关系,其中 Celebrity 有一个 HoneyBadger,那么您的原始设计将起作用。只需省略 HoneyBadger 方法并使用 honey_badger.celebrity_owner.birthdate 引用它们。 Django 会为你追踪外键。
  • 但我正在尝试从管理员那里引用这些字段,所以我不能只说 honey_badger.celebrity_owner.birthdate。
  • 哦,这是给管理员的。您可能认为名人_所有者_生日符号会起作用,但您的 HoneyBadger 管理员模型需要此猴子补丁:djangosnippets.org/snippets/2887
猜你喜欢
  • 2012-10-28
  • 2018-03-28
  • 2020-01-26
  • 2012-04-28
  • 1970-01-01
  • 1970-01-01
  • 2015-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多