Adding links to full change forms for inline items in django admin?

23,614

Solution 1

I had similar problem and I came up with custom widget plus some tweaks to model form. Here is the widget:

from django.utils.safestring import  mark_safe    

class ModelLinkWidget(forms.Widget):
    def __init__(self, obj, attrs=None):
        self.object = obj
        super(ModelLinkWidget, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        if self.object.pk:
            return mark_safe(
                u'<a target="_blank" href="../../../%s/%s/%s/">%s</a>' %\
                      (
                       self.object._meta.app_label,
                       self.object._meta.object_name.lower(),
                       self.object.pk, self.object
                       )
            )
        else:
            return mark_safe(u'')

Now since widget for each inline need to get different object in constructor you can't just set it in standard way, but in Form's init method:

class TheForm(forms.ModelForm):
    ...
    # required=False is essential cause we don't
    # render input tag so there will be no value submitted.
    link = forms.CharField(label='link', required=False)

    def __init__(self, *args, **kwargs):
        super(TheForm, self).__init__(*args, **kwargs)
        # instance is always available, it just does or doesn't have pk.
        self.fields['link'].widget = ModelLinkWidget(self.instance)

Solution 2

There is a property called show_change_link since Django 1.8.

Solution 3

I did something like the following in my admin.py:

from django.utils.html import format_html
from django.core.urlresolvers import reverse

class MyModelInline(admin.TabularInline):
    model = MyModel

    def admin_link(self, instance):
        url = reverse('admin:%s_%s_change' % (instance._meta.app_label,  
                                              instance._meta.module_name),
                      args=(instance.id,))
        return format_html(u'<a href="{}">Edit</a>', url)
        # … or if you want to include other fields:
        return format_html(u'<a href="{}">Edit: {}</a>', url, instance.title)

    readonly_fields = ('admin_link',)

Solution 4

The currently accepted solution here is good work, but it's out of date.

Since Django 1.3, there is a built-in property called show_change_link = True that addresses this issue.

This can be added to any StackedInline or TabularInline object. For example:

class ContactListInline(admin.TabularInline):
    model = ContactList
    fields = ('name', 'description', 'total_contacts',)
    readonly_fields = ('name', 'description', 'total_contacts',)
    show_change_link = True

The result will be something line this:

tabular inline using show_change_link

Solution 5

Quentin's answer above works, but you also need to specify fields = ('admin_link',)

Share:
23,614

Related videos on Youtube

David Eyk
Author by

David Eyk

Jack of all trades, master of webs. Asking all the wrong questions since I started teaching myself how to program Applesoft Basic in 1988. Continuing the tradition since joining SO in 2009.

Updated on July 09, 2022

Comments

  • David Eyk
    David Eyk almost 2 years

    I have a standard admin change form for an object, with the usual StackedInline forms for a ForeignKey relationship. I would like to be able to link each inline item to its corresponding full-sized change form, as the inline item has inlined items of its own, and I can't nest them.

    I've tried everything from custom widgets to custom templates, and can't make anything work. So far, the "solutions" I've seen in the form of snippets just plain don't seem to work for inlines. I'm getting ready to try some DOM hacking with jQuery just to get it working and move on.

    I hope I must be missing something very simple, as this seems like such a simple task!

    Using Django 1.2.

  • David Eyk
    David Eyk almost 14 years
    I haven't had time to try this, but it looks like it should work. :) Thanks.
  • Shai Berger
    Shai Berger about 11 years
    This is a fine solution, it can be made even more fine by combining it with stackoverflow.com/questions/5197280/…
  • Shai Berger
    Shai Berger about 11 years
    Also, this may be vulnerable to XSS attacks (depending on the objects presented and where they come from), and you really don't want those in the admin -- render the string with a Django Template instead of python's %.
  • jenny
    jenny about 11 years
    I've added this to my admin but I do not see the link. The column has been added tho. Any ideas?
  • freb
    freb over 10 years
    Nice solution. Very clean
  • elsadek
    elsadek almost 10 years
    when you save the edit form, it should return to the original parent edit page not to the change list of the edited object.
  • Serj Zaharchenko
    Serj Zaharchenko almost 9 years
    It seems that in Django 1.8 instead of instance._meta.module_name it should read instance._meta.model_name
  • adkl
    adkl about 6 years
    But what if I want a title to be a hyperlink, but not a label next to the title?
  • sheikhsalman08
    sheikhsalman08 almost 5 years
    True module_name should be model_name
  • Scratch'N'Purr
    Scratch'N'Purr over 4 years
    This solution works, but as noted from some of the other comments, use instance.pk instead of instance.id, instance._meta.model_name instead of instance._meta.module_name, and add admin_link to fields, e.g fields = (..., 'admin_link', ...)
  • Joe Sadoski
    Joe Sadoski over 2 years
    A quick note that you must register the model in the admin site (not just the inline), or the change link simply doesn't display above the inline (Django 3.2).