19

I've got a model (Entry) which contains a simple property:

@property
def image(self):
        return str(self.id)+"_"+self.round.season.name+"_"+self.round.theme+"_"+self.person.name

I use this to build the name of a particular image file on disk. So I know that there's going to be an image at /path/to/images/(model.image()).jpg

I can display the raw image property itself within the TabularInline layout on an admin page by adding it to the readonly_fields collection, but how would I go about getting a column which had custom html wrapped around the model property?

e.g.

<img src="/images/{{model.image}}.jpg" />
growse
  • 3,554
  • 9
  • 43
  • 66

4 Answers4

38

What you can do is create a method in your TabularInline subclass that returns the HTML you want, then use that method's name in place of image in ImageInline.fields:

from django.utils.safestring import mark_safe

class ImageInline(admin.TabularInline):
    ...
    fields = (..., 'render_image')
    readonly_fields = (..., 'render_image')

    def render_image(self, obj):
        return mark_safe("""<img src="/images/%s.jpg" />""" % obj.image)
Rintxy
  • 29
  • 7
gladysbixly
  • 2,591
  • 18
  • 15
  • 18
    When I try this, I get `"Unknown field(s) (render_image) specified for TheModelHere` – Matt Jul 14 '14 at 23:04
  • 45
    @Matt, that's because you need to specify that it's read only: `readonly_fields = (..., 'render_image')` – dragostis Aug 29 '14 at 12:51
  • And for those wondering why you need to specify that it's **read only**, as @dragostis mentioned, it's because when you customize the display format of a field, you're not representing the actual value of the field save in the db. On the contrary, when something is editable, it must be representing the actual value saved in the db, hence 'editing'. Hence, you can't have both customized representation and editability at the same time. – szamani20 Jan 31 '22 at 17:56
20

According to current Django 1.2+ I got errors "Form does not have such field as render_image". Solution is simple put the render_image function into model.Admin not in your inline form, second thing is fields and readonly_fields settings in your Inline form... So here You have what I've ended up with:

class OfferPropertyInline(admin.TabularInline):
    model = OfferProperty
    fields=('property_value',)
    readonly_fields = ('property_value',)

class OfferAdmin(admin.ModelAdmin):
    inlines = [
        OfferPropertyInline
    ]

    def property_value(self,obj):
        return obj.get_value()

admin.site.register(Offer, OfferAdmin)
lechup
  • 3,031
  • 27
  • 26
  • This is just great! Looks like a rough edge in django admin implementation though. If it can work in base admin class, it should work in inline too... – xaralis Jan 09 '12 at 15:29
3

Lechup's answer does not work for me, I am using Django 1.11.7. I found this way to work around.

Let say I have 2 tables: Campaign and Article, one campaign has many articles. I want to show the articles when browsing a specific campaign.

Table Article has a column named score, which is a float. I want to round it up to 2 decimal places when viewing in Django admin.

This example shows how you can make a custom column for TabularInline in Django admin.

class Article(models.Model):
    title = models.TextField(null=False)
    url = models.TextField()        
    score = models.FloatField(null=True)

    def __str__(self):
        return self.title

    def display_score(self):
        if self.score:
            return round(self.score, 2)
        return self.score

    display_score.short_description = 'Score'

class ArticleInline(admin.TabularInline):
    model = Article
    readonly_fields = ('title', 'url', 'display_score')
    fields = ('title', 'url', 'display_score')

class CampaignAdmin(admin.ModelAdmin):
    inlines = [ArticleInline]

admin.site.register(Campaign, CampaignAdmin)
Quan
  • 473
  • 7
  • 16
0

@lechup correct except you need:

readonly_fields = ('mycustomfield',)

defined in the Inline for later versions of django (+1.4)

Alexan
  • 8,165
  • 14
  • 74
  • 101