9

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]

I have an Inline question. When I pull up a Tournament in the Admin Site, I can see which players are going, and if they paid. I would also like to display extra information contained in Player, for example email address.

In TournamentPlayerInline I thought I might be able to get away with fields = ('player', 'paid', 'player_email') but I get FieldError: Unknown field(s) (player_email) specified for TournamentPlayer.

I also tried fields = ('player', 'paid', 'player__email'), but I get FieldError: Unknown field(s) (player__email) specified for TournamentPlayer.

If I move player_email from fields to readonly_fields, I no longer get the error, but the player email also isn't displayed either.

This is what I'm after:

enter image description here

How can I access Player properties from TournamentPlayerInline?

Django 1.8.4

epalm
  • 4,283
  • 4
  • 43
  • 65
  • Have you tried making the `player_email` a `@property`? You can also make it `fields = ('player', 'paid', 'player__email')` with the double underscore for a foreign key relationship. – Kyle Pittman Oct 06 '15 at 14:51
  • I added @property above `def player_email(self):`, no effect. Also tried player__email with no effect. – epalm Oct 06 '15 at 14:52
  • Hmm... Check out admin definitions shown in this question: http://stackoverflow.com/questions/163823/can-list-display-in-a-django-modeladmin-display-attributes-of-foreignkey-field – Kyle Pittman Oct 06 '15 at 14:53
  • Added `player_email.admin_order_field = 'player__email'` after `def player_email`, no effect. – epalm Oct 06 '15 at 14:55
  • Do you want the `player_email` to be editable in the admin? Otherwise you can just remove it from `fields` and add it to `readonly_fields` and this will work. – Kyle Pittman Oct 06 '15 at 15:13
  • No, `player_email` should not be editable. I moved it to `readonly_fields` and, while I don't get an error anymore, the player email still isn't displayed when viewing a Tournament. – epalm Oct 06 '15 at 16:17

3 Answers3

8

Monkey's answer is almost correct. The only change you have to make is to your admin.py, and it's merely adding 'player_email' to both fields as well as readonly_fields. Changing the position of 'player_email' in fields will allow you to order it as per your example.

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

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

If you do not require the player_email to be editable from the inline, then you can accomplish this with the readonly_fields variable:

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

@admin.register(Tournament)
class TournamentAdmin(admin.ModelAdmin):
    inlines = [TournamentPlayerInline]
Kyle Pittman
  • 2,858
  • 1
  • 30
  • 38
  • While this doesn't produce an error, it doesn't show the player email when viewing a Tournament either. This is what I'm after: http://i.imgur.com/IPIZNId.png – epalm Oct 06 '15 at 16:16
0

As an alternative, you do not have to define your custom property in your model if you're not using it directly, and just want to view it in admin -- you can create it in the Inline via a mixin:

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]

You could also make it a mailto URI this way:

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

This is known to work in Django 1.9.5

nicotine
  • 270
  • 3
  • 8