Temporary models in django

2019-06-21 21:20发布

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`')

2条回答
唯我独甜
2楼-- · 2019-06-21 21:36

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`')
查看更多
Luminary・发光体
3楼-- · 2019-06-21 21:55

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)
查看更多
登录 后发表回答