当Debug为False时,Admin中的Foreignkey链接导致AttributeError

Cra*_*oli 4 python django foreign-keys django-admin

我在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
Run Code Online (Sandbox Code Playgroud)

在admin.py list_display中,我已将link_to添加到我想要外键链接的每个字段的开头.这非常有效,但是当我关闭调试时,我得到一个属性错误.有什么建议?

小智 12

我偶然发现了同样的问题,幸运的是,我已经修好了.

原始解决方案(您使用的解决方案)来自这个问题,我的解决方案基于它:

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
Run Code Online (Sandbox Code Playgroud)

好吧,你唯一需要的是将原来的ModelAdminWithForeignKeyLinksMetaclass替换为上面的那个.

但是,这不是结束.最有趣的部分是原始解决方案导致问题的原因.这个问题的答案在这里(第31行)和这里(第244行).

当DEBUG打开时,Django会尝试验证所有已注册的ModelAdmins(第一个链接).有CLS是一 SomeAdmin(即它的元类的实例).当调用hasattr时,python尝试在类SomeAdmin或其一个超类中查找属性字段.由于它是不可能的,因此调用其类的__getattr__(即SomeAdmin的元类),其中将新方法添加到类SomeAdmin中.因此,在渲染界面时,SomeAdmin已经打补丁,Django能够找到所需的字段(第二个链接).

当DEBUG为False时,Django会跳过验证.当界面被渲染时,Django试图找到一个字段(再次,第二个链接),但这次SomeAdmin没有打补丁,而且model_admin不是类SomeAdmin,它是它的实例.因此,尝试在model_admin中查找属性名称时,python无法执行此操作,也无法在其类(SomeAdmin)及其任何超类中找到它,因此会引发异常.

  • 对我来说,这个解决方案会产生一个错误("元类冲突:由于某种原因,派生类的元类必须是其所有基类的元类的(非严格)子类").但是,在'django-model-admin-helper'中似乎有类似的版本适用于我(参见https://github.com/Arpaso/django-model-admin-helper/blob/master/中的代码SRC/admin_helpers.py) (2认同)