Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Temporary models in django

In one celery task I need to create temporary table in database. In this article Daniel Roseman explained how to create one. But this solution does not work in Django 1.9. I tried to look into Django docs and Google but I was unable to find anything useful.

Code from mentioned article which worked in Django 1.8:

from django.db import models, cursor
from django.contrib.contenttypes.management import update_contenttypes
from django.core.management import call_command

class TempCustomerAddress(models.Model):
    address = models.ForeignKey('accounts.Address')
    legacy_id = models.CharField(max_length=12, unique=True)

    class Meta:
        app_label = 'utils'


class Command(NoArgsCommand):

    def handle_noargs(self, **options):
        models.register_models('utils', TempCustomerAddress)
        models.signals.post_syncdb.disconnect(update_contenttypes)
        call_command('syncdb')

        # ... do importing and stuff referring to TempCustomerAddress ...

        cursor = connection.cursor()
        cursor.execute('DROP TABLE `utils_tempcustomeraddress`')
like image 425
Lamp town guy Avatar asked Jan 13 '16 14:01

Lamp town guy


2 Answers

In django 1.9 you actually don't need to register anything. You just create model the same way as in models.py and that's it. You only need to make sure that it is not in models.py file because than it will be permanent model. This example assumes that you already ran all migrations.

from django.db import models, cursor
from django.contrib.contenttypes.management import update_contenttypes
from django.core.management import call_command

class TempCustomerAddress(models.Model):
    address = models.ForeignKey('accounts.Address')
    legacy_id = models.CharField(max_length=12, unique=True)

    class Meta:
        app_label = 'utils'


class Command(NoArgsCommand):

    def handle_noargs(self, **options):
        with connection.cursor() as cursor:
            cursor.execute('DROP TABLE IF EXISTS utils_tempcustomeraddress')
            cursor.execute('''
                CREATE TABLE utils_tempcustomeraddress (
                    id INTEGER PRIMARY KEY NOT NULL,
                    address_id REFERENCES accounts_address (id),
                    legacy_id VARCHAR(12) UNIQUE
                );
            '''
            # ... do importing and stuff referring to TempCustomerAddress ...

            cursor.execute('DROP TABLE `utils_tempcustomeraddress`')
like image 125
Lamp town guy Avatar answered Oct 20 '22 07:10

Lamp town guy


I needed to create a temporary model derived from a "permanent" model, and use temporary table storage to avoid polluting the tables of the permanent one. After a lot of poking around including an article relating to Django 0.96, some newer material it points to for Django 1.2 and some old material based on migration tech integrated into Django I finally came up with a recipe that works with Django 2.0.

First, I needed to explicitly specify the database table name using the Meta:

model_name = re.sub('[@.]', '_', 'some_string')

class Meta:
    app_label = original_model._meta.app_label
    #
    # Use the explicit name for the database table.
    #
    db_table = '"' + model_name.lower() + '"'

Then I created the Model class by copying what I needed from the original:

attr = {'__module__': __name__, 'Meta': Meta}
local_fields = [field.name for field in original_model._meta.local_fields]
for field in original_model._meta.fields:
    #
    # Clone only the fields which we need, not forgetting that we only
    # want one primary key.
    #
    clone = field.clone()
    if field.name in local_fields:
        local_fields.remove(field.name)
    else:
        clone.primary_key = False
    if not isinstance(field, (db_models.AutoField, db_models.OneToOneField, db_models.ManyToManyField)):
        attr[field.name] = clone
new_model = type(model_name, (db_models.Model,), attr)

The hard part was tracking down how to create the new table for the model. Once found, the answer was simple:

from django.db import connection

with connection.schema_editor() as schema_editor:
    schema_editor.create_model(new_model)
like image 31
Shaheed Haque Avatar answered Oct 20 '22 08:10

Shaheed Haque