es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Puedo especificar un valor predeterminado personalizado que se utilizará al migrar después de agregar una nueva clase superior en un modelo Django?

Estoy escribiendo una aplicación Django que provee un modelo muy simple llamado Submittable, el cual los usuarios de la aplicación deben heredar cuando deseen usar otras funcionalidades de la app.


<h1>app1</h1> class Submittable(models.Model): is_submitted = models.BooleanField(default=False) # otros métodos aquí <h1>app2</h1> class Paper(Submittable): # algunos campos

Sin embargo, cuando agrego esto como padre en un modelo ya existente en otra aplicación y corro makemigrations, me pide proveer un valor por defecto para el nuevo campo submittable_ptr_id. El problema es que quiero que este campo simplemente apunte a una nueva instancia de Submittable, pero no sé cómo hacerlo.

Sé que podría simplemente editar el archivo de migración creado como se muestra a continuación:

class Migration(migrations.Migration):
    dependencies = [
        # algunas dependencias
    ]

    operations = [
        migrations.AddField(
            model_name='Paper',
            name='submittable_ptr_id',
            field=models.OneToOneField(auto_created=True, default=app1.utils.create_submittable, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='app1.Submittable'),
            preserve_default=False,
        ),
    ]

Pero quiero saber si puedo especificar algo en app1 para que esto suceda automáticamente. No quiero que los usuarios de la aplicación tengan que hacer este cambio por ellos mismos y en su lugar, cada vez que alguien hereda de Submittable y corre makemigrations, el valor por defecto debería ser simplemente establecido en esta función que crea un nuevo Submittable.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no hay una forma automática de establecer el valor predeterminado del campo submittable_ptr_id en una nueva instancia de Submittable cada vez que alguien hereda de Submittable. La razón es que cuando heredas de un modelo en Django, crea una nueva tabla en la base de datos con una clave externa que apunta al modelo padre. El campo submittable_ptr_id es la clave externa del modelo Submittable.

    Una solución, como mencionaste, es editar el archivo de migración y establecer el valor predeterminado en una función que crea un nuevo Submittable. Sin embargo, esto significa que los usuarios de la aplicación tendrán que modificar el archivo de migración ellos mismos.

    Otra solución es crear un comando de administración personalizado que genere un nuevo archivo de migración con el valor predeterminado establecido en la función que crea un nuevo Submittable. De esta manera, los usuarios de la aplicación pueden ejecutar este comando en lugar de editar manualmente el archivo de migración.

    Para crear un comando de administración personalizado, puedes seguir estos pasos:

    1. Crea un nuevo directorio llamado management en la raíz de tu aplicación de Django.
    2. Dentro del directorio management, crea otro directorio llamado commands.
    3. Dentro del directorio commands, crea un módulo Python llamado create_submittable_migration.py.
    4. Dentro del módulo create_submittable_migration.py, define un comando de administración personalizado que genere un nuevo archivo de migración con el valor predeterminado establecido en la función que crea un nuevo Submittable. Puedes usar la función call_command del módulo django.core.management para ejecutar el comando makemigrations con los argumentos adecuados. Aquí tienes un ejemplo:
    from django.core.management.base import BaseCommand, CommandError
    from django.core.management import call_command
    
    class Command(BaseCommand):
        help = 'Genera un nuevo archivo de migración con el valor predeterminado establecido en un nuevo Submittable'
    
        def handle(self, *args, **options):
            app_name = 'nombre_de_tu_aplicación' # reemplaza con el nombre de tu aplicación
            model_name = 'Submittable' # reemplaza con el nombre de tu modelo
            default_function = 'nombre_de_tu_aplicación.utils.create_submittable' # reemplaza con la función de valor predeterminado
    
            # genera un nuevo archivo de migración
            call_command('makemigrations', app_name, '--empty')
    
            # abre el nuevo archivo de migración y edita la lista de operaciones
            with open(f'{app_name}/migrations/0001_initial.py', 'r+') as f:
                content = f.read()
                i = content.index('operations = [') + len('operations = [')
                j = content.index(']', i)
                content = content[:i] + f'migrations.AddField(model_name=\'{model_name}\', name=\'submittable_ptr_id\', field=models.OneToOneField(auto_created=True, default={default_function}, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=\'{app_name}.{model_name}\'), preserve_default=False),' + content[j:]
                f.seek(0)
                f.write(content)
                f.truncate()
    
            self.stdout.write(self.style.SUCCESS('Archivo de migración creado correctamente'))
    
    1. Finalmente, los usuarios de la aplicación pueden ejecutar el comando de administración personalizado ejecutando python manage.py create_submittable_migration. Esto generará un nuevo archivo de migración con el valor predeterminado establecido en la función que crea un nuevo Submittable.

    Nota: Esta solución puede no ser ideal si el modelo Submittable tiene muchos campos o si la creación de un nuevo Submittable tiene muchas dependencias. En ese caso, puede ser mejor que los usuarios modifiquen el archivo de migración ellos mismos o que se proporcionen instrucciones más detalladas sobre cómo modificar el archivo de migración.

Comments are closed.