8

因此,对于 Django 项目,我真的希望能够动态生成和显示表(基于查询集),而无需事先知道内容或模式。

看起来django-tables2应用程序为呈现表格提供了很好的功能,但它要求您通过在自定义的 Table 子类上声明属性来显式声明列名,或者为其提供模型来推断列。

即,要使用名为“name”的列,您可以:

class NameTable(tables.Table):
   name = tables.Column()

Tables 类没有提供事后添加列的方法,因为从阅读源代码来看,它似乎使用了一个元类来扫描 __new__ 上的类属性并将它们锁定。

看起来非常简单的元编程将是一个优雅的解决方案。我定义了一个接受列名的基本类工厂是参数:

def define_table(columns):
    class klass(tables.Table): pass              
    for col in columns:
        setattr(klass, col, tables.Column())
    return klass

可悲的是,这不起作用。如果我运行`

x = define_table(["foo", "bar"])(data)
x.foo
x.bar

我回来了:

<django_tables2.columns.base.Column object at 0x7f34755af5d0>
<django_tables2.columns.base.Column object at 0x7f347577f750>

但是,如果我列出列:

print x.base_columns

我什么也没回来,即{}

我意识到可能有更简单的解决方案(例如,只是咬紧牙关并在代码中定义所有可能的数据配置,或者不使用 django-tables2 并自己动手),但我现在将此视为了解更多信息的机会元编程,所以我真的很想以这种方式进行这项工作。

知道我做错了什么吗?我的理论是 __new__ 方法(​​在表使用的元类中重新定义)在定义 klass 时而不是在实例化时被调用,所以当我添加属性时为时已晚。但这违反了我对何时 __new__ 应该发生的理解。否则,我很难理解元类 __new__ 如何区分代码中定义的属性与动态定义的属性之间的区别。

谢谢!

4

2 回答 2

6

您在这里走在正确的轨道上,但是您应该使用type()内置函数,而不是创建准系统类并向其添加属性。它没有按照您尝试的方式工作的原因是因为元类已经完成了它的工作。

Usingtype()允许您使用自己的属性构造一个新类,同时设置基类。含义 - 您可以将所需的字段描述为类的蓝图,允许Tables 元类在您的定义之后接管。

type()这是与 django 一起使用的示例。我自己将它用于我自己的项目(有一些细微的变化),但考虑到你已经快到那里了,它应该给你一个很好的起点。

def define_table(columns):
    attrs = dict((c, tables.Column()) for c in columns)
    klass = type('DynamicTable', (tables.Table,), attrs)
    return klass
于 2013-01-03T07:15:28.237 回答
1

您将__new__“常规”类与__new__元类混淆了。正如您所注意到的,它Table依赖__new__于其metaclass上的方法。定义类时确实调用了元类。类本身就是元类的一个实例,所以定义类就是实例化元类。(在这种情况下,Table是 的一个实例DeclarativeColumnMetaClass。)所以当类被定义时,为时已晚。

一种可能的解决方案是编写Table具有某种方法等的子类refreshColumns。您可以调整代码从DeclarativeColumnMetaclass.__new__本质上refreshColumns再次发挥同样的魔力。然后你可以打电话refreshColumns()给你的新班级。

于 2013-01-03T07:16:58.613 回答