Login

Replace model select widget in admin with a readonly link to the related object

Author:
ekellner
Posted:
August 28, 2008
Language:
Python
Version:
.96
Score:
6 (after 6 ratings)

This replaces the html select box for a foreign key field with a link to that object's own admin page. The foreign key field (obviously) is readonly.

This is shamelessly based upon the Readonly admin fields snippet. However, that snippet didn't work for me with ForeignKey fields.

from foo.bar import ModelLinkAdminFields

class MyModelAdmin(ModelLinkAdminFields, admin.ModelAdmin):
    modellink = ('field1', 'field2',)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from django import forms
from django.utils.safestring import mark_safe
from django.utils.html import escape

class ModelLinkWidget(forms.HiddenInput):

    def __init__(self, admin_site, original_object):
        self.admin_site = admin_site
        self.original_object = original_object
        super(ModelLinkWidget,self).__init__()

   
    def render(self, name, value, attrs=None):
        if self.original_object is not None:
            link = '%s%s/%s/%d' % (self.admin_site.root_path,
                                   self.original_object._meta.app_label, 
                                   self.original_object._meta.module_name,
                                   self.original_object.id)
            return super(ModelLinkWidget, self).render(
                name, value, attrs) + mark_safe('<a href="%s">%s</a>' % (link, escape(unicode(self.original_object))))
        else:
            return "None"
                                                                
class ModelLinkAdminFields(object):
    def get_form(self, request, obj=None):
        form = super(ModelLinkAdminFields, self).get_form(request, obj)

        if hasattr(self, 'modellink'):
            for field_name in self.modellink:
                if field_name in form.base_fields:
                    form.base_fields[field_name].widget = ModelLinkWidget(self.admin_site, getattr(obj, field_name, ''))
                    form.base_fields[field_name].required = False
        return form

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

romke (on December 12, 2008):

I'd put "self.original_object.pk" instead of "self.original_object.id" as sometimes you have primary key named differently than "id"

#

paulmcm (on February 11, 2009):

This worked for me, except when I wanted to add a new item in the admin containing the field in question (I was using it to show ID fields).

The fix (for me) was to modify line 13 to read:

        if (self.original_object is not None) and (hasattr(self.original_object, '_meta')):

now it no longer throws the error for me.

#

graeme (on June 28, 2009):

I was getting errors when there was a null value in a foreign key (pointing to User).

Changing some lines in ModelLinkAdminFields fixed it:

    if hasattr(self, 'modellink'):
        for field_name in self.modellink:
            if field_name in form.base_fields:
                try:
                    y = getattr(obj, field_name, None)
                except:
                    y = None
                form.base_fields[field_name].widget = ModelLinkWidget(self.admin_site, y)

I am not sure this is the best only way, and only fields that had been filled in by django-evolution caused problems, so this probably will not affect everyone.

#

Please login first before commenting.