Create tables dynamically and operate them through Django ORM.
Dynamically creating a model is actually to generate the Model class at runtime. This can be achieved through a function, passing parameters (today's date, such as: 20181211), and then generating a new model class. The db_table
in Meta is 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 # This is the name of the Model.
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
As you can see, different Log Classes are generated through functions. Pay attention to LogMetaclass
and __metaclass__. Metaclasses
can change the name of the model at runtime. The name of the table can be defined by db_table
, and the name of the class can be defined by overriding the metaclass.
print cls.__name__
Log_20181211
print cls._meta.db_table
log_20181211
Use the direct function to obtain the Log model of the current date, and then use is_exists to determine whether the table is created, and create the corresponding table if it is not created.
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.
# As mentioned in the above warning, Django does not recommend reloading Model definitions.
# As a demo, it can be obtained directly through get_log_model, ignoring the warning.
# So here first get the registered Model through all_models,
# If it is not available, generate a new 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)
Get the cls part above, the code here is first obtained through the registered all_models
of apps, otherwise the second execution of a model definition code will throw a RuntimeWarning
warning, the model will be registered in the initialization function of the model, it is best not to repeat the registration . First get the model through apps.get_model
, if not, then initialize the new model through get_log_model
. This is a bit safer.