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,
},
),
]