尝试向Python类(即django-tables2';Table';)动态添加方法时遇到问题

尝试向Python类(即django-tables2';Table';)动态添加方法时遇到问题,python,django,metaprogramming,django-tables2,Python,Django,Metaprogramming,Django Tables2,因此,对于Django项目,我非常希望能够动态生成和显示表(而不是基于QuerySet的),而无需事先知道内容或模式 看起来该应用程序为呈现表提供了很好的功能,但它要求您通过在自定义定义的表子类上声明属性来显式声明列名,或者为其提供一个模型来推断列 也就是说,要使用名为“name”的列,您需要执行以下操作: class NameTable(tables.Table): name = tables.Column() Tables类不提供事后添加列的方法,因为从读取源代码时,它似乎使用了一个

因此,对于Django项目,我非常希望能够动态生成和显示表(而不是基于QuerySet的),而无需事先知道内容或模式

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

也就是说,要使用名为“name”的列,您需要执行以下操作:

class NameTable(tables.Table):
   name = tables.Column()
Tables类不提供事后添加列的方法,因为从读取源代码时,它似乎使用了一个元类,该元类在_unew_u上扫描类属性并将其锁定

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

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>
我什么也没得到,即{}

我意识到可能有更简单的解决方案(例如,咬紧牙关,在代码中定义每一种可能的数据配置,或者不使用django-tables2并使用我自己的),但我现在将此视为了解更多元编程的机会,所以我真的希望这样做

知道我做错了什么吗?我的理论是uuu new_uuu方法(在元类表使用中重新定义)在定义klass时被调用,而不是在实例化klass时被调用,所以当我添加属性时已经太迟了。但这违背了我对什么时候应该发生新的事情的理解。否则,我很难理解元类new如何区分代码中定义的属性和动态定义的属性


谢谢

在这里,您的思路是正确的,但是您应该使用内置函数,而不是创建一个barebones类并向其添加属性。它没有按照您尝试的方式工作的原因是元类已经完成了它的工作

使用
type()
可以使用自己的属性构造一个新类,同时设置基类。意思-你可以将你想要的字段作为蓝图描述给你的类,允许
的元类在你定义之后接管

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

def define_table(columns):
    attrs = dict((c, tables.Column()) for c in columns)
    klass = type('DynamicTable', (tables.Table,), attrs)
    return klass

你把一个“常规”类的
\uuuuuuuuuuuuuuuuuuuuuuuuu
和一个元类的
\uuuuuuuuuuuuuuuuuuuuuuuuuu
搞混了。正如您所注意到的,
依赖其元类上的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法。定义类时,确实会调用元类。类本身就是元类的实例,因此定义类就是实例化元类。(在本例中,
Table
DeclarativeColumnMetaClass
的一个实例),因此在定义该类时,为时已晚


一种可能的解决方案是编写一个
子类,该子类具有一些方法
刷新列
或类似方法。您可以调整
DeclarativeColumnMetaclass.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。然后,您可以在新类上调用
refreshColumns()

Awesome。这管用!或者,仅仅做
table.base_columns[col]=col
似乎是可行的,但这可能破坏了我没有看到的东西,因为它绕过了列创建代码。因此,您的解决方案要好得多。未来的读者也应该看看@BrenBarn的答案,因为它解释了我的方法失败的原因。@Rogueleader很高兴它对你有用。在你的脑海中,你应该阅读元类,以及它们提供的各种功能。在玩Django时,了解它们特别有用,因为模型和表单都使用它们,有时您需要深入了解细节。谢谢您的回答!我认为Josh的回答稍微优雅一点,但你的回答有助于解释我的方法失败的原因。
def define_table(columns):
    attrs = dict((c, tables.Column()) for c in columns)
    klass = type('DynamicTable', (tables.Table,), attrs)
    return klass