在 Django 框架中使用动态模型
Using dynamic models in Django framework
我目前正在使用 Django 框架,包括它的模型机制来抽象数据库模式声明和一般数据库访问,这在大多数情况下都可以正常工作。
但是,我的应用程序还需要在运行时动态创建和访问 tables,据我所知,开箱即用的 Django 不支持这一点。
这些table通常具有相同的结构,基本上可以被同一个模型class抽象出来,但是Django不允许你改变某个模型查询的底层db_table,如它是在模型 class 上声明的,而不是在管理器上声明的。
我的解决方案是每当我需要创建、填充和访问新的 table 时执行此过程:
- 使用原始 sql
创建并填充 table
- 使用原始 sql
将索引添加到 table
当我需要访问 table(使用 django queryset api)时,我动态声明了一个新类型并且 return 它作为模型查询,使用此代码:
table_name = # name of the table created by sql
model_name = '%d_%s' % (connection.tenant.id, table_name)
try:
model = apps.get_registered_model('myapp', model_name)
return model
except LookupError:
pass
logger.debug("no model exists for model %s, creating one" % model_name)
class Meta:
db_table = table_name
managed = False
attrs = {
'field1' : models.CharField(max_length=200),
'field2' : models.CharField(max_length=200),
'field3' : models.CharField(max_length=200)
'__module__': 'myapp.models',
'Meta':Meta
}
model = type(str(model_name), (models.Model,), attrs)
return model
请注意,我会检查该模型是否已在 django 中注册,并且我正在使用现有模型以防万一。每个 table 的模型名称始终是唯一的。由于我使用的是多租户,因此租户名称也是模型名称的一部分,以避免与在不同模式上声明的类似 table 发生冲突。
- 以防万一:动态创建的 tables 将而且应该永久保留以供将来的会话使用。
到目前为止,这个解决方案对我来说效果很好。
但是,应用程序需要支持大量这样的 table。即 10,000 - 100,000 个这样的 tables(和相应的模型 classes),每个 table.
最多一百万行
假设底层数据库可以承受此负载,我的问题是:
无论是否考虑到预期规模,您是否发现此解决方案有任何问题?
有人对此场景有更好的解决方案吗?
谢谢。
有一个关于动态创建模型的 wiki 页面,尽管自上次更新以来已经有一段时间了:
还有一些专为该用例设计的应用程序,但我认为没有任何应用程序得到积极维护:
Django Packages: Dynamic models
我知道,如果您已经致力于 Django,这不是很有帮助,但这是一个 Django 不太适合的用例。与 Django 的模型层提供的抽象作斗争可能比仅使用 psycopg2 或任何其他适合您的数据的适配器成本更高。
根据您要对数据执行的操作类型,使用带有索引字段的单个模型可能更合理,这样您就可以区分 table 该行将然后按该列对数据进行分片。
如果你还需要这样做,一般的想法是:
创建一个扩展 Django 的 ModelBase 的元类。您可以将此元类用作实际模型的工厂。
考虑该 wiki 页面上提到的内容,例如规避 app_label 问题。
生成并执行 sql 以创建模型,如维基页面上所示。
我目前正在使用 Django 框架,包括它的模型机制来抽象数据库模式声明和一般数据库访问,这在大多数情况下都可以正常工作。
但是,我的应用程序还需要在运行时动态创建和访问 tables,据我所知,开箱即用的 Django 不支持这一点。
这些table通常具有相同的结构,基本上可以被同一个模型class抽象出来,但是Django不允许你改变某个模型查询的底层db_table,如它是在模型 class 上声明的,而不是在管理器上声明的。
我的解决方案是每当我需要创建、填充和访问新的 table 时执行此过程:
- 使用原始 sql 创建并填充 table
- 使用原始 sql 将索引添加到 table
当我需要访问 table(使用 django queryset api)时,我动态声明了一个新类型并且 return 它作为模型查询,使用此代码:
table_name = # name of the table created by sql model_name = '%d_%s' % (connection.tenant.id, table_name) try: model = apps.get_registered_model('myapp', model_name) return model except LookupError: pass logger.debug("no model exists for model %s, creating one" % model_name) class Meta: db_table = table_name managed = False attrs = { 'field1' : models.CharField(max_length=200), 'field2' : models.CharField(max_length=200), 'field3' : models.CharField(max_length=200) '__module__': 'myapp.models', 'Meta':Meta } model = type(str(model_name), (models.Model,), attrs) return model
请注意,我会检查该模型是否已在 django 中注册,并且我正在使用现有模型以防万一。每个 table 的模型名称始终是唯一的。由于我使用的是多租户,因此租户名称也是模型名称的一部分,以避免与在不同模式上声明的类似 table 发生冲突。
- 以防万一:动态创建的 tables 将而且应该永久保留以供将来的会话使用。
到目前为止,这个解决方案对我来说效果很好。
但是,应用程序需要支持大量这样的 table。即 10,000 - 100,000 个这样的 tables(和相应的模型 classes),每个 table.
最多一百万行
假设底层数据库可以承受此负载,我的问题是:
无论是否考虑到预期规模,您是否发现此解决方案有任何问题?
有人对此场景有更好的解决方案吗?
谢谢。
有一个关于动态创建模型的 wiki 页面,尽管自上次更新以来已经有一段时间了:
还有一些专为该用例设计的应用程序,但我认为没有任何应用程序得到积极维护:
Django Packages: Dynamic models
我知道,如果您已经致力于 Django,这不是很有帮助,但这是一个 Django 不太适合的用例。与 Django 的模型层提供的抽象作斗争可能比仅使用 psycopg2 或任何其他适合您的数据的适配器成本更高。
根据您要对数据执行的操作类型,使用带有索引字段的单个模型可能更合理,这样您就可以区分 table 该行将然后按该列对数据进行分片。
如果你还需要这样做,一般的想法是:
创建一个扩展 Django 的 ModelBase 的元类。您可以将此元类用作实际模型的工厂。
考虑该 wiki 页面上提到的内容,例如规避 app_label 问题。
生成并执行 sql 以创建模型,如维基页面上所示。