前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django 一个模型不同Table的操作

Django 一个模型不同Table的操作

作者头像
用户1416054
发布2018-12-25 11:49:43
1.9K0
发布2018-12-25 11:49:43
举报
文章被收录于专栏:JackeyGao的博客JackeyGao的博客

Django 一个模型不同Table的操作

Posted December 11, 2018

教程代码托管在 JackeyGao / django-dynamic-tables

用过 Django 框架的都知道, 模型定义是开发一个项目前面需要做的事情, 后面通过导入的方式在 View 中操作。 这样的流程是 Django 默认的流程, 但流程是一成不变的吗? 大多数时候, 我们的设计的系统, Django 默认的框架都不能适用, Django 的确封装了很多功能组件,让MVT架构更有效率的开发, 您在设计的时候必须按照它们设计好的框架里面设计程序。 但今天要讲是一种比较干燥的方式

假设我有一个需求是一个日志表(log),需要动态的根据每天生成结果表(log_20181211, log_20181212)。

默认情况下, 我们需要定义Model

models.py

Python

代码语言:javascript
复制
class Log(models.Model):
    level = models.IntegerField(choices=LOG_LEVELS)
    msg = models.TextField()
    time = models.DateTimeField(auto_now=True, auto_now_add=True)

    class Meta:
        db_table = "log"

然后通过 migrate 创建表, 这样的代码很属于 Django 风格,但实现不了我们的需求。 默认的 Django ORM 操作没有根据时间切割表. migrate 之后这张表就已经永久创建了。 后面操作这个 Model 一直在操作 log 这张表.

动态的创建表

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

Python

代码语言: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定义, 类的名称可以通过覆盖元类的方法定义。

Python

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

使用

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

Python

代码语言: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初始化新的模型. 这样做更加稳妥一点.

代码托管在 JackeyGao / django-dynamic-tables

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Django 一个模型不同Table的操作
    • 动态的创建表
      • 使用
      相关产品与服务
      代码托管
      CODING 代码托管(CODING Code Repositories,CODING-CR)是为开发者打造的云端便捷代码管理工具,旨在为更多的开发者带去便捷、高效的开发体验,全面支持 Git/SVN 代码托管,包括代码评审、分支管理、超大仓库等功能。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档