Skip to content Skip to sidebar Skip to footer

Display Foreign Key Columns As Link To Detail Object In Django Admin

As explained in link-in-django-admin-to-foreign-key-object, one can display a ForeignKey field as a link to the admin detail page. To summarize, class Foo(Model): bar = models.

Solution 1:

The solution below uses this answer but makes it reusable by all models, avoiding the need to add methods to each admin class.

Example Models

# models.pyfrom django.db import models

class Country(models.Model):
    name = models.CharField(max_length=200)
    population = models.IntegerField()

class Career(models.Model):
    name = models.CharField(max_length=200)
    average_salary = models.IntegerField()

class Person(models.Model):
    name = models.CharField(max_length=200)
    age = models.IntegerField()
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    career = models.ForeignKey(Career, on_delete=models.CASCADE)

Example Admin

# admin.pyfrom django.utils.html import format_html
from django.urls import reverse

from .models import Person


deflinkify(field_name):
    """
    Converts a foreign key value into clickable links.
    
    If field_name is 'parent', link text will be str(obj.parent)
    Link will be admin url for the admin url for obj.parent.id:change
    """def_linkify(obj):
        linked_obj = getattr(obj, field_name)
        if linked_obj isNone:
            return'-'
        app_label = linked_obj._meta.app_label
        model_name = linked_obj._meta.model_name
        view_name = f'admin:{app_label}_{model_name}_change'
        link_url = reverse(view_name, args=[linked_obj.pk])
        return format_html('<a href="{}">{}</a>', link_url, linked_obj)

    _linkify.short_description = field_name  # Sets column namereturn _linkify



@admin.register(Person)classPersonAdmin(admin.ModelAdmin):
    list_display = [
        "name",
        "age",
        linkify(field_name="country"),
        linkify(field_name="career"),
    ]

Results

Given an App named app, and a Person instance Person(name='Adam' age=20) with country and carreer foreign key values with ids 123 and 456, the list result will be:

| Name | Age |                          Country                          |...|
|------|-----|-----------------------------------------------------------|...|
| Adam |  20 | <ahref="/admin/app/country/123">Country object(123)</a>  |...|

(Continues)

|...|                          Career                         |
|---|---------------------------------------------------------|
|...| <ahref="/admin/app/career/456">Career object(456)</a>  |

Solution 2:

A good start would be looking at the source of BaseModelAdmin and ModelAdmin. Try to find out how the ModelAdmin generates the default links. Extend ModelAdmin, add a method to generate links to arbitrary foreign keys and look at how ChangeList generates the change list.

I would also suggest you use format_html to render the links, which makes link_to_bar.allow_tags = True unnecessary:

from django.utils.html import format_html

classFooAdmin(ModelAdmin):
    list_display = ('link_to_bar', )
    deflink_to_bar(self, obj):
        link = urlresolvers.reverse('admin:app_bar_change', args=[obj.bar_id])
        return format_html('<a href="{}">{}</a>', link, obj.bar) if obj.bar elseNone

Solution 3:

A slight respin on the accepted answer. It is not necessarily better, but implements some of the advice in the comments:

from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
from django.utils.html import format_html


deflinkify(field_name):
    def_linkify(obj):
        content_type = ContentType.objects.get_for_model(obj)
        app_label = content_type.app_label
        linked_obj = getattr(obj, field_name)
        linked_content_type = ContentType.objects.get_for_model(linked_obj)
        model_name = linked_content_type.model
        view_name = f"admin:{app_label}_{model_name}_change"
        link_url = reverse(view_name, args=[linked_obj.pk])
        return format_html('<a href="{}">{}</a>', link_url, linked_obj)

    _linkify.short_description = field_name.replace("_", " ").capitalize()
    return _linkify

Post a Comment for "Display Foreign Key Columns As Link To Detail Object In Django Admin"