在 Django 框架中使用动态模型

Posted

技术标签:

【中文标题】在 Django 框架中使用动态模型【英文标题】:Using dynamic models in Django framework 【发布时间】:2015-10-28 09:32:34 【问题描述】:

我目前正在使用 Django 框架,包括其模型机制来抽象数据库模式声明和一般数据库访问,这在大多数情况下都可以正常工作。 但是,我的应用程序还需要在运行时动态创建和访问表,据我所知,Django 不支持开箱即用。 这些表通常具有相同的结构,并且基本上可以被同一个 Model 类抽象出来,但是 Django 不允许您更改某个模型查询的底层 db_table,因为它是在 Model 类上声明的,而不是在 Manager 上声明的。

我的解决方案是在需要创建、填充和访问新表时执行此过程:

使用原始 sql 创建和填充表 使用原始 sql 向表中添加索引

当我需要访问表时(使用 django queryset api),我动态声明一个新类型并将其作为查询模型返回,使用以下代码:

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 中注册,并且我正在使用现有模型以防万一。每个表的模型名称始终是唯一的。由于我使用的是多租户,因此租户名称也是模型名称的一部分,以避免与在不同架构上声明的类似表发生冲突。

如果不清楚:动态创建的表将并且应该永久保留以供将来的会话使用。

到目前为止,此解决方案对我来说效果很好。 但是,应用程序将需要支持大量此类表。即 10,000 - 100,000 个这样的表(和相应的模型类),每个表最多有一百万行。 假设底层数据库可以承受这种负载,我的问题是:

您是否认为此解决方案存在任何问题,无论是否考虑预期规模?

对于这种情况,有人有更好的解决方案吗?

谢谢。

【问题讨论】:

你熟悉ContentTypes吗? 谢谢。是的,我是,简短地说。但我看不出它如何有助于在运行时创建模型。不过,如果它已经注册,它可能有助于替换我检索现有模型的方式。 相关:***.com/questions/7933596/django-dynamic-model-fields 【参考方案1】:

有一个关于动态创建模型的 wiki 页面,尽管距离上次更新已经有一段时间了:

DynamicModels Django

还有一些应用程序是为这个用例设计的,但我认为它们中的任何一个都没有得到积极维护:

Django Packages: Dynamic models

我知道,如果您已经致力于 Django,这不是很有帮助,但这是一个 Django 不是很好的用例。与 Django 模型层提供的抽象作斗争可能比仅使用 psycopg2 或任何其他适合您的数据的适配器成本更高。

根据您要对数据执行的操作类型,使用具有索引字段的单个模型可能更合理,该索引字段允许您区分该行将在哪个表中,然后对数据进行分片按该列。

如果您仍然需要这样做,一般的想法是:

    创建一个扩展 Django 模型库的元类。您可以将此元类用作实际模型的工厂。

    考虑该 wiki 页面上提到的内容,例如规避 app_label 问题。

    生成并执行用于创建模型的 sql,如 wiki 页面上所示。

【讨论】:

非常感谢托马斯。正如你提到的,这些包没有维护,所以我不想使用它们。 wiki 页面基本上是我的方法所依据的,实际上我的下一步是按照您的建议更密切地遵循它。分片也是一个有趣的想法,但我目前不需要它,而且这样做似乎有点矫枉过正,因为 Django 不容易支持动态建模。

以上是关于在 Django 框架中使用动态模型的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中动态生成导入,专门针对 Django 模型

如何在 Django 中使用动态外键?

Django REST框架:在ModelViewSet中保存相关模型

django中的Model模型一:

Django:从 Pandas 到 Django Rest 框架的模型查询集

Django DetailView 动态模型