在 Django 管理站点中,如何通过内联访问模型属性?

Posted

技术标签:

【中文标题】在 Django 管理站点中,如何通过内联访问模型属性?【英文标题】:In the Django Admin Site, how can I access model properties through an Inline? 【发布时间】:2016-01-03 12:58:02 【问题描述】:

models.py:

class Player(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=50)

class Tournament(models.Model):
    name = models.CharField(max_length=50)

class TournamentPlayer(models.Model):
    tournament = models.ForeignKey(Tournament)
    player = models.ForeignKey(Player)
    paid = models.BooleanField()

    def player_email(self):
        return self.player.email

admin.py:

class TournamentPlayerInline(admin.TabularInline):
    model = TournamentPlayer
    fields = ('player', 'paid', 'player_email')

@admin.register(Tournament)
class TournamentAdmin(admin.ModelAdmin):
    inlines = [TournamentPlayerInline]

我有一个内联问题。当我在管理站点中启动锦标赛时,我可以看到哪些玩家参加了比赛,以及他们是否付费。我还想显示 Player 中包含的额外信息,例如电子邮件地址。

在 TournamentPlayerInline 中,我认为我可能能够摆脱 fields = ('player', 'paid', 'player_email'),但我得到 FieldError: Unknown field(s) (player_email) specified for TournamentPlayer

我也试过fields = ('player', 'paid', 'player__email'),但我得到FieldError: Unknown field(s) (player__email) specified for TournamentPlayer

如果我将player_emailfields 移动到readonly_fields,我将不再收到错误消息,但也不会显示玩家电子邮件。

这就是我所追求的:

如何从 TournamentPlayerInline 访问 Player 属性?

Django 1.8.4

【问题讨论】:

您是否尝试过将player_email 设为@property?您也可以使用双下划线将其设为 fields = ('player', 'paid', 'player__email') 以表示外键关系。 我在def player_email(self):上方添加了@property,没有效果。也试过 player__email 没有效果。 嗯...查看此问题中显示的管理员定义:***.com/questions/163823/… def player_email之后添加了player_email.admin_order_field = 'player__email',没有效果。 您希望player_email 在管理员中可编辑吗?否则,您只需将其从 fields 中删除并将其添加到 readonly_fields 即可。 【参考方案1】:

Monkey 的回答几乎是正确的。您需要做的唯一更改是您的admin.py,它只是将'player_email' 添加到fieldsreadonly_fields。在fields 中更改'player_email' 的位置将允许您按照您的示例对其进行排序。

class TournamentPlayerInline(admin.TabularInline):
    model = TournamentPlayer
    fields = ('player', 'player_email', 'paid',)
    readonly_fields = ('player_email',)

@admin.register(Tournament)
class TournamentAdmin(admin.ModelAdmin):
    inlines = [TournamentPlayerInline]

【讨论】:

【参考方案2】:

如果您不要求可以从内联编辑 player_email,那么您可以使用 readonly_fields 变量来完成此操作:

class TournamentPlayerInline(admin.TabularInline):
    model = TournamentPlayer
    fields = ('player', 'paid')
    readonly_fields = ('player_email',)

@admin.register(Tournament)
class TournamentAdmin(admin.ModelAdmin):
    inlines = [TournamentPlayerInline]

【讨论】:

虽然这不会产生错误,但在查看锦标赛时也不会显示玩家电子邮件。这就是我所追求的:i.imgur.com/IPIZNId.png【参考方案3】:

作为替代方案,如果您不直接使用它,则不必在模型中定义您的自定义属性,而只想在管理员中查看它——您可以通过 mixin 在 Inline 中创建它:

models.py

class Player(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=50)

class Tournament(models.Model):
    name = models.CharField(max_length=50)

class TournamentPlayer(models.Model):
    tournament = models.ForeignKey(Tournament)
    player = models.ForeignKey(Player)
    paid = models.BooleanField()

admin.py

class PlayerEmailMixin(object):
    def player_email(self, obj):
        return obj.player.email

    player_email.short_description = "Player Email"

class TournamentPlayerInline(PlayerEmailMixin, admin.TabularInline):
    model = TournamentPlayer
    fields = ('player', 'player_email', 'paid', )
    readonly_fields = ('player_email',)

@admin.register(Tournament)
class TournamentAdmin(admin.ModelAdmin):
    inlines = [TournamentPlayerInline]

您也可以通过这种方式将其设为 mailto URI:

class PlayerEmailMixin(object):
    def player_email(self, obj):
        return '<a href="mailto:0"><strong>0</strong></a>'.format(obj.player.email)

    player_email.short_description = "Player Email"
    player_email.allow_tags = True

这在 Django 1.9.5 中是已知的

【讨论】:

以上是关于在 Django 管理站点中,如何通过内联访问模型属性?的主要内容,如果未能解决你的问题,请参考以下文章

django:管理站点中模型的自定义名称

如何在字段集中显示Django管理员内联模型?

管理站点中的 Django DateTimeField 编辑

如何在 django 管理页面上创建锚点以自动从 url 向下滚动到内联或字段

Django 管理员自定义验证 - 至少需要一个内联外键模型

ForeignKey 字段不会出现在 Django 管理站点中