動态建立table, 并通過 Django ORM 操作.
動态的建立表
動态的建立模型其實就是在運作時生成 Model 類, 這個可以通過函數實作, 通過傳參(今天的日期, 如: 20181211),然後生成新的模型類, Meta 中的 db_table 為log_20181211.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定義, 類的名稱可以通過覆寫元類的方法定義。print cls.__name__
Log_20181211
print cls._meta.db_table
log_20181211
使用
使用直接通過函數, 擷取目前日期的 Log 模型, 然後通過is_exists判讀表是否建立, 沒有建立則建立對應的表.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('
%s
' % cls._meta.db_table)
上面擷取 cls 部分, 這裡的代碼先通過apps的已經注冊的 all_models 擷取, 否則一個模型的第二次執行定義代碼就會抛出RuntimeWarning警告, 在模型的初始化函數都會注冊此模型, 最好不要重複注冊. 先通過 apps.get_model 擷取這個模型, 如果沒有擷取到則通過get_log_model初始化新的模型. 這樣做更加穩妥一點.