Home > Enterprise >  Dynamic table creation on a Django Model save
Dynamic table creation on a Django Model save

Time:10-03

I would like to create additional tables when I call model.save() (INSERT). But I keep getting this error:

django.db.transaction.TransactionManagementError: Executing DDL statements while in a transaction on databases that can't perform a rollback is prohibited.

I tried to create additional tables inside model.save() and using a pre_save() signal, I get the same error.

This is a pre_save solution attempt:

from django.db import connection
from django.db.models.signals import pre_save
from django.dispatch import receiver


@receiver(pre_save, sender=MyModel, dispatch_uid="create_tags")
def create_tags(sender, instance, **kwargs):
    print("debug, signal pre_save works") 
    try:
        # if obj exists in MyModel table, skip tag table creation
        existing_obj = MyModel.objects.get(name=instance.name)
        print("debug, obj exists")
    except MyModel.DoesNotExist:
        with connection.schema_editor() as schema_editor:
            schema_editor.create_model(MyModel2)

Stack: Django, MySQL.

What I want to implement is to create additional tables for the instance that is being inserted.

To clarify how the miscellaneous per-instance tables are generated, this is the code to derive a per-instance table. For example, for every inserted car instance, there are to be generated miscellaneous Tag tables with sensor measurements:

def get_tag(car_url, car_type):
    class Tag(models.Model):
        time = models.PositiveIntegerField(primary_key=True)  # unix time in seconds  # noqa
        value = models.FloatField()

        class Meta:
            db_table = car_url   "_"   car_type

        def __str__(self) -> str:
            return str(self.time)   ","   str(self.value)

    return Tag

I think that the probable solution is to use "nonatomic" somewhere in the code.

CodePudding user response:

Temporarily set schema_editor.connection.in_atomic_block = False.

with connection.schema_editor() as schema_editor:
    in_atomic_block = schema_editor.connection.in_atomic_block
    schema_editor.connection.in_atomic_block = False
    try:
        schema_editor.create_model(MyModel2)
    finally:
        schema_editor.connection.in_atomic_block = in_atomic_block

Using a context manager:

with connection.schema_editor() as schema_editor:
    with non_atomic(schema_editor):
        schema_editor.create_model(MyModel2)
from contextlib import contextmanager


@contextmanager
def non_atomic(schema_editor):
    in_atomic_block = schema_editor.connection.in_atomic_block
    schema_editor.connection.in_atomic_block = False
    try:
        yield
    finally:
        schema_editor.connection.in_atomic_block = in_atomic_block
  • Related