Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic models django

Let's say i have 10 tables in 1 Db and the table names differ and data is different, but the structure of the tables are the same. And then i have 1 more table that collects all the table names and the creation date of that table.

Example:

PrimaryTable
table_name_1
table_name_2
....
table_name_10

and the structure of all tables example:

class PrimaryTable(models.Model):
    name = models.CharField(db_column='Name', unique=True, max_length=100)
    date = models.CharField(db_column='Date', max_length=100)

    class Meta:
        managed = True
        db_table = 'Primary Table'

    def __str__(self):
        return self.name


class table_name_1(models.Model):
    title = models.TextField(db_column='Title', blank=True, null=True)
    url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
                           null=True)
    description = models.TextField(db_column='Description', blank=True, null=True)
    created_at = models.DateTimeField(db_column='Created_at')


class table_name_2(models.Model):
    title = models.TextField(db_column='Title', blank=True, null=True)
    url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
                           null=True)
    description = models.TextField(db_column='Description', blank=True, null=True)
    created_at = models.DateTimeField(db_column='Created_at')

and so on...

And i only want to make 1 class that includes all those tables that have same structure and call it when i choose the table from the PrimaryTable.

I don't want to use "python manage.py inspectdb > models.py" every time i create a table. I want to have access to the new created table instantly when i create it.

like image 308
Omega Avatar asked Jun 29 '26 22:06

Omega


2 Answers

You can define your model fields as dict:

fields = dict(
    title = models.TextField(db_column='Title', blank=True, null=True),
    url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True, null=True),
    description = models.TextField(db_column='Description', blank=True, null=True),
    created_at = models.DateTimeField(db_column='Created_at'),
)

Then you can dynamicly create and run migration for it:

from django.db import connection, migrations, models
from django.db.migrations.executor import MigrationExecutor

def create_table(table_name, model_fields, app_label):
    class Migration(migrations.Migration):
        initial = True
        dependencies = []
        operations = [
            migrations.CreateModel(
                name=table_name,
                fields=[
                    ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ] + [(k, field) for k,field in model_fields.items()],
                options={
                    'db_table': table_name,
                },
            ),
        ]
    executor = MigrationExecutor(connection)
    migration = Migration(table_name, app_label)
    with connection.schema_editor(atomic=True) as schema_editor:
        migration.apply(executor._create_project_state(), schema_editor)

Then you can use dynamic model creation to access data in tables:

from django.db import models

def create_model(name, fields=None, app_label=None, module='', options=None, admin_opts=None):
    """
    Create specified model
    """
    class Meta:
        db_table = name
    if app_label:
        # app_label must be set using the Meta inner class
        setattr(Meta, 'app_label', app_label)
    # Update Meta with any options that were provided
    if options is not None:
        for key, value in options.iteritems():
            setattr(Meta, key, value)
    # Set up a dictionary to simulate declarations within a class
    attrs = {'__module__': module, 'Meta': Meta}
    # Add in any fields that were provided
    if fields:
        attrs.update(fields)
    # Create the class, which automatically triggers ModelBase processing
    model = type(name, (models.Model,), attrs)
    return model

I hope you will get general idea. I took code from project that uses Django 2 (similar code is used to create tables per uploaded CSV file, columns and name of each uploaded CSV is stored in table which is similar to your PrimaryTable).

like image 141
Viktor Danyliuk Avatar answered Jul 02 '26 12:07

Viktor Danyliuk


You can simplify things by keeping all of the data with the same structure in one table. You can use admin filters and custom manager methods to focus on one type of information at a time, which will provide the same functionality as separate tables.

class Information(models.Model):
    name = models.CharField(db_column='Name', unique=True, max_length=100)
    date = models.CharField(db_column='Date', max_length=100)
    information_type = models.ForeignKey(InformationType, related_name='information_records')

    def __str__(self):
        return self.name


class InformationType(models.Model):
    title = models.TextField(db_column='Title', blank=True, null=True)
    url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
                           null=True)
    description = models.TextField(db_column='Description', blank=True, null=True)
    created_at = models.DateTimeField(db_column='Created_at')

    def __str__(self):
        return self.title
like image 36
evergreen Avatar answered Jul 02 '26 11:07

evergreen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!