Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

289
Views
Migración condicional de Django basada en un campo solo presente en la nueva versión

Mi aplicación que actualmente depende de Postgres y Django's Postgres-only JSONField . El campo funciona bien y no tengo ningún interés en otro proyecto, pero tengo usuarios potenciales que quieren usar mi aplicación, pero no pueden mientras dependa de Postgres.

Django 3.1 tiene una versión multiplataforma de este campo —que funcionará para mis necesidades— pero no quiero obligar a todo el mundo a usar Django 3.1; Me gustaría ofrecer a la gente la posibilidad de elegir entre Postgres o Django 3.1+. Sobre el papel, esto es bastante simple con una importación condicional...

 try: from django.db.models import JSONField except ImportError: from django.contrib.postgres.fields import JSONField

Y si instalé Django 3.1 y generé una migración, podría llevarme de django.contrib.postgres.fields.JSONField a django.db.models.JSONField . Pero...

  • Los nuevos usuarios seguirán ejecutando la migración inicial. Todavía tendré una dependencia en Postgres.
  • Los usuarios de Sub-Django 3.1 no podrán ejecutar la nueva migración. Ahora tengo una dependencia de Django 3.1.

Esto es peor que cuando empecé. ¿Cómo hago este tipo de migración de campo de una manera que funcione para todos?

over 4 years ago · Santiago Trujillo
4 answers
Answer question

0

Las migraciones son solo código. El hecho de que se generen automáticamente no significa que no deba cambiarlos. Lo alentamos a que, al menos, verifique que se generen correctamente, pero tampoco hay nada de malo en escribirlos usted mismo.

Esto funciona para mí:

Modelo:

 from django.db import models try: from django.db.models import JSONField except ImportError: from django.contrib.postgres.fields import JSONField class MyModel(models.Model): stuff = JSONField()

Migración:

 from django.db import migrations, models try: from django.db.models import JSONField except ImportError: from django.contrib.postgres.fields import JSONField class Migration(migrations.Migration): dependencies = [('testapp', '0001_initial')] operations = [ migrations.CreateModel( name='MyModel', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('stuff', JSONField()), ], ), ]

Tenga en cuenta que si necesita cambiar este campo en el futuro, deberá realizar este proceso nuevamente.

over 4 years ago · Santiago Trujillo Report

0

Tengo esto del código fuente de Django

 from django.db.models import JSONField as BuiltinJSONField class JSONField(BuiltinJSONField): system_check_deprecated_details = { 'msg': ( 'django.contrib.postgres.fields.JSONField is deprecated. Support ' 'for it (except in historical migrations) will be removed in ' 'Django 4.0.' ), 'hint': 'Use django.db.models.JSONField instead.', 'id': 'fields.W904', }

Esto indica que django.contrib.postgres.fields.JSONField quedará en desuso. Además, Django usa django.db.models.JSONField como JSONField especial de postgres.

Aparte de eso, generé el comando SQL usando el comando sqlmigrate y fue como,

 BEGIN; -- -- Create model MyModel -- CREATE TABLE "myapp_mymodel" ("id" serial NOT NULL PRIMARY KEY, "stuff" jsonb NOT NULL); COMMIT;

Sorprendentemente, tengo el mismo comando SQL usando Django==3.0 y Django==3.1 y en la base de datos, el campo es de tipo jsonb

Esta información concluye que no tiene que preocuparse por esta nueva actualización de JSONField.

¿Qué cambios hay que hacer?

No necesita generar un nuevo archivo de migración , pero edite los archivos de migración existentes que tienen una referencia django.contrib.postgres.fields.JSONField con el bloque try...except .

¡¡¡Eso es todo!!!

over 4 years ago · Santiago Trujillo Report

0

Le di un punto a Tom Carrick por su respuesta, pero creo que también debería incluir el uso deMeta.required_db_vendor = 'postgres' en Django <3.1

 # models.py from django.db import models try: from django.db.models import JSONField postgres_only = False except ImportError: from django.contrib.postgres.fields import JSONField postgres_only = True class MyModel(models.Model): stuff = JSONField() class Meta: if postgres_only: required_db_vendor = 'postgres'
 # migrations/0001_initial.py from django.db import migrations, models try: from django.db.models import JSONField postgres_only = False except ImportError: from django.contrib.postgres.fields import JSONField postgres_only = True class Migration(migrations.Migration): dependencies = [('testapp', '0001_initial')] operations = [ migrations.CreateModel( name='MyModel', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('stuff', JSONField()), ], options={'required_db_vendor': 'postgres'} if postgres_only else None, ), ]

Esto asegurará que los usuarios de su aplicación reutilizable no puedan usarla en una base de datos diferente a PostgreSQL en Django < 3.1 y habilitará sin problemas el soporte en 3.1 sin requerir una migración en los usuarios de PostgreSQL que usen su biblioteca y actualicen a Django 3.1.

over 4 years ago · Santiago Trujillo Report

0

Todas las nuevas migraciones se corregirán automáticamente si se utiliza esta solución con un método deconstruct() .

Puede crear un JSONField personalizado compatible que encapsule ambas variantes.

Cree un pequeño archivo fields.py en su aplicación:

 try: from django.db.models import JSONField as OrigJSONField except ImportError: from django.contrib.postgres.fields import JSONField as OrigJSONField class JSONField(OrigJSONField): def deconstruct(self): # the original path was 'django.db.models.JSONField' or 'django.contrib.postgres.fields....' name, path, args, kwargs = super().deconstruct() # Substitute 'my_app' by your application name everywhere. path = 'my_app.fields.JSONField' return name, path, args, kwargs

Cambie una línea en su models.py :

 from my_app.fields import JSONField

Edite todas las migraciones existentes que usan un JSONField:

 import my_app.fields ... ('stuff', my_app.fields.JSONField()),

(o equivalente)

 from my_app.fields import JSONField ... ('stuff', JSONField()).

No se crea ninguna migración después de eso porque makemigrations no encuentra ninguna diferencia.

Todas las futuras makemigrations después de un modelo modificado se crearán automáticamente con my_app.fields.JSONField() . La compatibilidad es un beneficio de esta solución.


Reflexión sobre Django Release Notes 3.1 y futuras:

Describen una actualización simple que requiere crear una nueva migración que solo actualice la ruta de importación, pero no genera SQL, por ejemplo, mediante sqlmigrate . Es más fácil que editar migraciones antiguas.

Tal vez usted también actualice en dos años a Django >= 3.1 solamente y tendrá dos alternativas:

A) Solo se editará la importación en models.py y creará una nueva migración formal casi vacía de manera similar a las notas de la versión. No podrá eliminar la ruta de importación my_app.fields.JSONField porque debe poder importarse de migraciones antiguas de manera similar que Django nunca puede eliminar la ruta django.contrib.postgres.fields.JSONField . El archivo my_app/fields.py podría simplificarse a una línea from django.db.models import JSONField as JSONField después de una actualización incondicional de requisitos.

B) Es posible volver a editar las migraciones antiguas solo al nuevo JSONField, pero no es razonable.

(Es responsabilidad de cada usuario que una edición en un archivo de migraciones no requiera un estado de base de datos modificado y todas las migraciones permanezcan consistentes entre sí. Es por eso que no se puede encontrar mucho al respecto, excepto casos claros).

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!