Django dynamically creates multiple table names of a model and operates them through Django ORM

created at 07-17-2021 views: 2

Create tables dynamically and operate them through Django ORM.

Dynamically create tables

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

usage

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.

Please log in to leave a comment.