django 组装表名查询数据(动态表名、组合表名)

2023-02-18 13:48:56 浏览数 (1)

了解 getattr 函数

教程:https://www.runoob.com/python/python-func-getattr.html

描述

getattr() 函数用于返回一个对象属性值。

语法

getattr 语法:

代码语言:javascript复制
getattr(object, name[, default])

参数

  • object -- 对象。
  • name -- 字符串,对象属性。
  • default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。

返回值

返回对象属性值。

适用情景

数据表名有一定的规律,根据表名的规律来选择数据表。比如:表名是 user_101, user_102, user_103 以此类推,有规律可循。

组装表名查询

代码语言:javascript复制
import myapp.models

def test(requset):
    user_db_name = "user_%s" % request.user.name  # 组装表名
    user_db = getattr(myapp.models, user_db_name)
    user_data = user_db.objects.all()
    
    rerurn "..."

一个模型动态创建的多个 db_table

出处:http://www.chenxm.cc/article/764.html

动态创建 table, 并通过 Django ORM 操作.

动态的创建表

动态的创建模型其实就是在运行时生成 Model 类, 这个可以通过函数实现, 通过传参(今天的日期, 如: 20181211),然后生成新的模型类, Meta 中的 db_table 为 log_20181211.

代码语言:javascript复制
def get_log_model(prefix):
    table_name = 'log_%s' % str(prefix)

    LOG_LEVELS = (
        (0, 'DEBUG'),
        (10, 'INFO'),
        (20, 'WARNING'),
    )

    class LogMetaclass(models.base.ModelBase):
        def __new__(cls, name, bases, attrs):
            name  = '_'   prefix  # 这是Model的name.
            return models.base.ModelBase.__new__(cls, name, bases, attrs)

    class Log(models.Model):
        __metaclass__ = LogMetaclass
        level = models.IntegerField(choices=LOG_LEVELS)
        msg = models.TextField()
        time = models.DateTimeField(auto_now=True, auto_now_add=True)

        @staticmethod
        def is_exists():
            return table_name in connection.introspection.table_names()

        class Meta:
            db_table = table_name

    return Log

可以看到, 通过函数生成不同的 Log Class. 注意 LogMetaclass 和 __metaclass__ , 元类可以在运行时改变模型的名字,table 的名称我们可以通过 db_table 定义, 类的名称可以通过覆盖元类的方法定义。

代码语言:javascript复制
print cls.__name__
Log_20181211
print cls._meta.db_table
log_20181211

使用

使用直接通过函数, 获取当前日期的 Log 模型, 然后通过 is_exists 判读表是否创建, 没有创建则创建对应的表.

代码语言:javascript复制
def index(request):
    today = date.today().strftime("%Y%m%d")

    # RuntimeWarning: Model '__main__.logclasslog_' was already registered.
    # Reloading models is not advised as it can lead to inconsistencies
    # most notably with related models.
    # 如上述警告所述, Django 不建议重复加载 Model 的定义.
    # 作为 demo 可以直接通过get_log_model获取,无视警告.
    # 所以这里先通过 all_models 获取已经注册的 Model,
    # 如果获取不到, 再生成新的模型.
    try:
        cls = apps.get_model('__main__', 'Log_%s' % today)
    except LookupError:
        cls = get_log_model(today)

    if not cls.is_exists():
        with connection.schema_editor() as schema_editor:
            schema_editor.create_model(cls)

    log = cls(level=10, msg="Hello")
    log.save()

    return HttpResponse('<h1>%s</h1>' % cls._meta.db_table)

上面获取 cls 部分, 这里的代码先通过 apps 的已经注册的 all_models 获取, 否则一个模型的第二次执行定义代码就会抛出 RuntimeWarning 警告, 在模型的初始化函数都会注册此模型, 最好不要重复注册. 先通过 apps.get_model 获取这个模型, 如果没有获取到则通过 get_log_model 初始化新的模型. 这样做更加稳妥一点.

0 人点赞