在Django框架中使用动态模型

sin*_*ton 7 python django postgresql django-models django-queryset

我目前正在使用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
    
    Run Code Online (Sandbox Code Playgroud)
  • 请注意,我确实检查模型是否已在django中注册,并且我正在使用现有模型.模型名称对于每个表始终是唯一的.由于我使用的是多租户,因此租户名称也是模型名称的一部分,以避免与在不同模式上声明的类似表冲突.

  • 如果不清楚:动态创建的表将永久保留以供将来的会话使用.

到目前为止,这个解决方案对我来说很好 但是,应用程序需要支持大量这些表.即10,000 - 100,000个这样的表(和相应的模型类),每个表有多达一百万行.

假设这个负载的基础数据库很好,我的问题是:

  • 您是否看到此解决方案有任何问题,无论是否达到预期规模?

  • 任何人都有更好的解决方案吗?

谢谢.

Tom*_*ena 5

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

动态模型 Django

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

Django 包:动态模型

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

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

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

  1. 创建一个扩展 Django 的 ModelBase 的元类。您将使用此元类作为实际模型的工厂。

  2. 考虑该 wiki 页面上提到的内容,例如绕过 app_label 问题。

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