I have used the following code in my models.py file:
Create hyperlink to foreignkey
class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass):
I uses stepank's implementation, but had to alter it slightly to fit my use-case.
I basically just added support for 'ModelAdmin.readonly_fields' and 'ModelAdmin.fields' to support the 'link_to_'-syntax.
A slight change to the link creation also allowed me to support a link to a different APP.Model, in my case the built-in django.contrib.auth.models.user.
Thanks for the nice work @stepank and @Itai Tavor.
I hope this is useful for somebody else.
DEFAULT_LOGGER_NAME is defined in my settings.py and I use it for most of my logging. If you don't have it defined, you will get errors when using the following code. You can either define your own DEFAULT_LOGGER_NAME in settings.py (it is just a simple string) or you just remove all references to the logger in the code below.
'''
Created on Feb 23, 2012
@author: daniel
Purpose: Provides a 'link_to_' function for ModelAdmin
implementations. This is based on the following work:
original: http://stackoverflow.com/a/3157065/193165
fixed original: http://stackoverflow.com/a/7192721/193165
'''
from functools import partial
from django.forms import MediaDefiningClass
import logging
from public.settings import DEFAULT_LOGGER_NAME
logger = logging.getLogger(DEFAULT_LOGGER_NAME)
class ForeignKeyLinksMetaclass(MediaDefiningClass):
def __new__(cls, name, bases, attrs):
new_class = super(
ForeignKeyLinksMetaclass, cls).__new__(cls, name, bases, attrs)
def foreign_key_link(instance, field):
target = getattr(instance, field)
ret_url = u'%s' % (
target._meta.app_label, target._meta.module_name,
target.id, unicode(target)
)
#I don't know how to dynamically determine in what APP we currently
#are, so this is a bit of a hack to enable links to the
#django.contrib.auth.models.user
if "auth" in target._meta.app_label and "user" in target._meta.module_name:
ret_url = u'%s' % (
target._meta.app_label, target._meta.module_name,
target.id, unicode(target)
)
return ret_url
def _add_method(name):
if name is None: return
if isinstance(name, basestring) and name[:8] == 'link_to_':
try:
method = partial(foreign_key_link, field=name[8:])
method.__name__ = name[8:]
method.allow_tags = True
#in my app the "user" field always points to django.contrib.auth.models.user
#and I want my users to see that when they edit "client" data
#"Client" is another model, that has a 1:1 relationship with
#django.contrib.auth.models.user
if "user" in name[8:]:
method.short_description = "Auth User"
setattr(new_class, name, method)
except Exception, ex:
logger.debug("_add_method(%s) failed: %s" % (name, ex))
#make this work for InlineModelAdmin classes as well, who do not have a
#.list_display attribute
if hasattr(new_class, "list_display") and not new_class.list_display is None:
for name in new_class.list_display:
_add_method(name)
#enable the 'link_to_' syntax for the ModelAdmin.readonly_fields
if not new_class.readonly_fields is None:
for name in new_class.readonly_fields:
_add_method(name)
#enable the 'link_to_' syntax for the ModelAdmin.fields
if not new_class.fields is None:
for name in new_class.fields:
_add_method(name)
return new_class