Link To Foreignkey in Admin Causes AttributeError When Debug Is False

前端 未结 2 913
深忆病人
深忆病人 2021-02-04 21:21

I have used the following code in my models.py file:

Create hyperlink to foreignkey

class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass): 
         


        
2条回答
  •  忘掉有多难
    2021-02-04 21:55

    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
    

提交回复
热议问题