天天看點

django orm原理_django 動态建立一個模型的多個table name, 并通過 Django ORM 操作%s

動态建立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初始化新的模型. 這樣做更加穩妥一點.