Saltar al contenido

Campos del modelo de Django con nombres dinámicos

Solución:

Los modelos de Django se pueden crear con nombres de campo dinámicos. Aquí hay un modelo simple de Django:

class Animal(models.Model):
    name = models.CharField(max_length=32)

Y aquí está la clase equivalente construida usando type():

attrs = {
    'name': models.CharField(max_length=32),
    '__module__': 'myapp.models'
}
Animal = type("Animal", (models.Model,), attrs)

Cualquier modelo de Django que se pueda definir de la manera normal se puede hacer usando type().

Para ejecutar migraciones: South tiene un conjunto confiable de funciones para manejar migraciones de esquemas y bases de datos para proyectos de Django. Cuando se utiliza en desarrollo, South puede sugerir migraciones pero no intenta aplicarlas automáticamente

from south.db import db
model_class = generate_my_model_class()
fields = [(f.name, f) for f in model_class._meta.local_fields]
table_name = model_class._meta.db_table
db.create_table(table_name, fields)
# some fields (eg GeoDjango) require additional SQL to be executed
db.execute_deferred_sql()

La forma más limpia probablemente sería usar add_to_class():

ModelOne.add_to_class(
    '%s_title' % field_prefix, 
    models.CharField(max_length=255, blank=True, default="")
)

Aún así, esto puede considerarse “parcheado” con todas sus desventajas, como hacer que la aplicación sea más difícil de mantener, tener un código que sea más difícil de entender, etc. Pero si su caso de uso hace que sea realmente necesario hacer algo así, probablemente sería la mejor solución ya que add_to_class() es una funcionalidad proporcionada por el propio Django y se ha mantenido estable durante bastante tiempo.

Intente usar un patrón de fábrica para configurar sus diferentes versiones de AbstractModel.

Con este enfoque, puede controlar más estrictamente la forma AbstractModel se modifica mediante la función de fábrica dynamic_fieldname_model_factory.

Tampoco estamos modificando ModelOne o ModelTwo después de sus definiciones, otras soluciones han señalado que esto ayuda a evitar problemas de mantenibilidad.

modelos.py:

from django.db import models


def dynamic_fieldname_model_factory(fields_prefix):
    class AbstractModel(models.Model):

        class Meta:
            abstract = True

    AbstractModel.add_to_class(
        fields_prefix + '_title',
        models.CharField(max_length=255, blank=True, default=""),
    )
    return AbstractModel


class ModelOne(dynamic_fieldname_model_factory('someprefix1')):
    id = models.AutoField(primary_key=True)


class ModelTwo(dynamic_fieldname_model_factory('someprefix2')):
    id = models.AutoField(primary_key=True)

Aquí está la migración generada por este código:

# Generated by Django 2.1.7 on 2019-03-07 19:53

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name="ModelOne",
            fields=[
                ('someprefix1_title', models.CharField(blank=True, default="", max_length=255)),
                ('id', models.AutoField(primary_key=True, serialize=False)),
            ],
            options={
                'abstract': False,
            },
        ),
        migrations.CreateModel(
            name="ModelTwo",
            fields=[
                ('someprefix2_title', models.CharField(blank=True, default="", max_length=255)),
                ('id', models.AutoField(primary_key=True, serialize=False)),
            ],
            options={
                'abstract': False,
            },
        ),
    ]
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *