Python 当调试为False时,管理中指向Foreignkey的链接会导致AttributeError

Python 当调试为False时,管理中指向Foreignkey的链接会导致AttributeError,python,django,django-admin,foreign-keys,Python,Django,Django Admin,Foreign Keys,我在models.py文件中使用了以下代码: 创建指向foreignkey的超链接 class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass): def __getattr__(cls, name): def foreign_key_link(instance, field): target = getattr(instance, field) re

我在models.py文件中使用了以下代码:

创建指向foreignkey的超链接

class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass): 

    def __getattr__(cls, name):

        def foreign_key_link(instance, field):
            target = getattr(instance, field)
            return u'<a href="../../%s/%s/%s">%s</a>' % (
                target._meta.app_label, target._meta.module_name, target.id, unicode(target))

        if name[:8] == 'link_to_':
            method = partial(foreign_key_link, field=name[8:])
            method.__name__ = name[8:]
            method.allow_tags = True
            setattr(cls, name, method)
            return getattr(cls, name)
        raise AttributeError
class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass):
def_u_getattr__(cls,名称):
def外键链接(实例,字段):
target=getattr(实例,字段)
返回u'%(
目标。_meta.app_标签,目标。_meta.module_名称,target.id,unicode(目标))
如果名称[:8]=“链接到”:
方法=部分(外键链接,字段=名称[8:])
方法。\名称\名称=name[8:]
method.allow_tags=True
setattr(cls、名称、方法)
返回getattr(cls,名称)
提高属性错误

在admin.py list_display中,我将link_添加到每个字段的开头,我想要一个foreignkey链接。这工作得非常好,但是当我关闭调试时,会出现属性错误。有什么建议吗?

我偶然发现了完全相同的问题,幸运的是,我已经解决了

原始解决方案(您使用的解决方案)来自,我的解决方案基于此:

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)
            return u'<a href="../../%s/%s/%d/">%s</a>' % (
                target._meta.app_label, target._meta.module_name,
                target.id, unicode(target)
            )

        for name in new_class.list_display:
            if name[:8] == 'link_to_':
                method = partial(foreign_key_link, field=name[8:])
                method.__name__ = name[8:]
                method.allow_tags = True
                setattr(new_class, name, method)

        return new_class
class ForeignKeyLinksMetaclass(MediaDefiningClass):
定义(cls、名称、基数、属性):
新类=超级(
ForeignKeyLinksMetaclass,cls)。\uuuu新建(cls,名称,基础,属性)
def外键链接(实例,字段):
target=getattr(实例,字段)
返回u'%(
目标。_meta.app_标签,目标。_meta.module_名称,
target.id,unicode(目标)
)
对于“新建类列表”显示中的名称:
如果名称[:8]=“链接到”:
方法=部分(外键链接,字段=名称[8:])
方法。\名称\名称=name[8:]
method.allow_tags=True
setattr(新类、名称、方法)
返回新的\u类
好的,您只需要用上面的模型替换原始模型AdminWithForeignKeyLinksMetaClass

然而,这并不是结束。最有趣的部分是为什么原始解决方案会导致问题。这个问题的答案是(第31行)和(第244行)

当DEBUG开启时,Django尝试验证所有注册的ModelAdmins(第一个链接)。cls有一个SomeAdmin(即其元类的实例)。当调用hasattr时,python会尝试在类SomeAdmin或它的一个超类中查找属性字段。因为这是不可能的,所以会调用其类(即SomeAdmin的元类)的_getattr _uu,其中会向类SomeAdmin添加一个新方法。因此,在呈现界面时,SomeAdmin已经打了补丁,Django能够找到所需的字段(第二个链接)


如果DEBUG为False,Django将跳过验证。当接口呈现为Django时,Django尝试查找一个字段(同样是第二个链接),但这次SomeAdmin没有修补,而且model_admin不是类SomeAdmin,它是它的实例。因此,试图在model_admin中找到属性名,python无法做到这一点,也无法在其类(SomeAdmin)以及任何超类中找到它,因此引发了一个异常。

我使用stepank的实现,但不得不稍微修改它以适应我的用例

我基本上只是添加了对'ModelAdmin.readonly_fields'和'ModelAdmin.fields'的支持,以支持'link_to_'-语法

对链接创建的轻微更改还允许我支持指向不同APP.Model的链接,在我的例子中是内置的django.contrib.auth.models.user

感谢stepank和Itai Tavor的出色工作

我希望这对其他人有用


默认_LOGGER_名称在my settings.py中定义,我在大多数日志记录中都使用它。如果没有定义它,则在使用以下代码时会出现错误。您可以在settings.py中定义自己的默认\u LOGGER\u名称(它只是一个简单的字符串),也可以在下面的代码中删除对记录器的所有引用

'''
Created on Feb 23, 2012

@author: daniel

Purpose: Provides a 'link_to_<foreignKeyModel>' 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'<a href="../../%s/%s/%d/">%s</a>' % (
                      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'<a href="/admin/%s/%s/%d/">%s</a>' % (
                          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_<foreignKeyModel>' 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_<foreignKeyModel>' syntax for the ModelAdmin.fields
        if not new_class.fields is None:
            for name in new_class.fields:
                _add_method(name)

        return new_class
“”
创建于2012年2月23日
@作者:丹尼尔
用途:为ModelAdmin提供“链接到”功能
实现。这是基于以下工作:
原件:http://stackoverflow.com/a/3157065/193165
固定原件:http://stackoverflow.com/a/7192721/193165
'''
从functools导入部分
从django.forms导入MediaDefiningClass
导入日志记录
从public.settings导入默认\u记录器\u名称
logger=logging.getLogger(默认的记录器名称)
类别ForeignKeyLinksMetaclass(MediaDefiningClass):
定义(cls、名称、基数、属性):
新类=超级(
ForeignKeyLinksMetaclass,cls)。\uuuu新建(cls,名称,基础,属性)
def外键链接(实例,字段):
target=getattr(实例,字段)
ret_url=u'%(
目标。_meta.app_标签,目标。_meta.module_名称,
target.id,unicode(目标)
) 
#我不知道如何动态确定我们当前使用的应用程序
#是的,所以启用到
#django.contrib.auth.models.user
如果在target.\u meta.app.\u标签中有“auth”,在target.\u meta.module.\u名称中有“user”:
ret_url=u'%(
目标。_meta.app_标签,目标。_meta.module_名称,
target.id,unicode(目标)
)                    
返回ret_url
定义添加方法(名称):
如果name为None:返回
如果isinstance(名称、基串)和name[:8]=“链接到”:
尝试:
方法=部分(外键链接,字段=名称[8:])
方法。\名称\名称=name[8:]
method.allow_tags=True
#在我的应用程序中,“用户”字段始终指向django.contrib.auth.models.user
#我希望我的用户在下载时看到这一点