El misterio que casi me vuelve loco empezó con un síntoma extraño: la aplicación Django funcionaba perfectamente en local, pero tras desplegar en staging y UAT algunas relaciones muchos a muchos dejaban de guardarse sin dar error. Formularios se enviaban, el panel de administración indicaba operación correcta, las respuestas API devolvían éxito, pero las relaciones M2M no se creaban. No había pistas visibles, solo datos que desaparecían en el aire y un dolor de cabeza para quien lo investiga.
Contexto técnico: la aplicación tenía modelos Employee, SegregationType, Item y Skill, y tres de ellos tenían ManyToManyField hacia Skill. En local todo era normal, pero en entornos preproducción al intentar asignar skills a SegregationType o Item la operación parecía completarse pero no quedaban filas en la tabla intermedia.
Tras descartar frontend, serialización y posibles problemas de red o condiciones de carrera, apareció una pista en los logs: django.db.utils.IntegrityError duplicate key value violates unique constraint django_migrations_pkey DETAIL Key (id)=(3) already exists. Ahí se encendió la luz: el problema eran las secuencias de PostgreSQL desincronizadas.
Por qué pasa esto: al restaurar bases de datos a partir de backups las filas se insertan, pero las secuencias que controlan los valores autoincrementales no siempre se actualizan al máximo id actual. El resultado es que la secuencia cree que el próximo id disponible es pequeño mientras la tabla ya contiene filas con ids altos, provocando conflictos de clave primaria y fallos silenciosos en operaciones que dependen de nuevos ids.
La primera solución que apliqué fue recorrer todos los modelos principales y resetear sus secuencias con setval y pg_get_serial_sequence para que la secuencia quede por encima del máximo id presente. Eso resolvió los problemas en las tablas de los modelos que aparecen en apps.get_models, pero el fallo persistía para ciertas relaciones M2M.
La pieza que faltaba: Django crea tablas intermedias implícitas para ManyToManyField cuando no se define un through explícito. Esas tablas implican un id autoincremental propio y, por tanto, sus propias secuencias. apps.get_models no devuelve esas tablas implícitas, de modo que sus secuencias seguían desincronizadas tras la restauración y las inserciones en la tabla intermedia fallaban silenciosamente o eran ignoradas por operaciones que creían haber escrito las relaciones.
Cómo detectarlo: comprobar los nombres de tabla de las through tables usando model.field.through._meta.db_table para cada campo many_to_many y verificar el máximo id y la secuencia asociada. Ejemplo de consulta SQL orientativa para una tabla intermedia llamada jobs_segregationtype_skills: SELECT setval(pg_get_serial_sequence(jobs_segregationtype_skills,id),COALESCE(MAX(id),1),true) FROM jobs_segregationtype_skills; Esta consulta ajusta la secuencia para que continúe después del id más alto presente.
Solución completa y repetible: crear un comando de management que recorra todos los modelos principales y además identifique los campos many_to_many para procesar sus tablas through implícitas. Para cada tabla identificar la secuencia con pg_get_serial_sequence y ejecutar setval con COALESCE(MAX(id),1) o con MAX(id)+1 según se prefiera el comportamiento. Ejecutar este script siempre después de una restauración de base de datos evita estos problemas silenciosos.
Buenas prácticas y prevención: al generar dumps y backups incluir las secuencias o ejecutar un paso post restore que ajuste todas las secuencias; incorporar tests de integración que verifiquen la persistencia de relaciones M2M en entornos de staging; automatizar este chequeo en la pipeline de despliegue; y monitorizar excepciones IntegrityError para detectar de inmediato conflictos de claves primarias. Además, documentar el procedimiento en la guía de operaciones para que no dependa de la memoria de una sola persona.
Ejemplo de checklist post restore: ejecutar script de reset de secuencias para modelos principales y para tablas through implícitas, validar que las inserciones nuevas generan ids consecutivos sin conflictos, y correr pruebas que creen y lean relaciones M2M. Con esto se evita que fallos pasen desapercibidos y se mantiene la integridad referencial.
Lecciones aprendidas: los fallos silenciosos son los más peligrosos porque consumen mucho tiempo de diagnóstico; la complejidad implícita de Django al crear tablas intermedias es fácil de pasar por alto; y la paridad entre entornos es crítica para evitarlos. La gestión de secuencias en PostgreSQL tras una restauración es una tarea imprescindible en cualquier proyecto Django con relaciones many to many.
Cómo puede ayudar Q2BSTUDIO: en Q2BSTUDIO somos especialistas en desarrollo de software a medida y aplicaciones a medida y acompañamos a equipos técnicos desde el diseño hasta la operación. Si necesitas auditar tus despliegues, automatizar post restores en bases de datos PostgreSQL o asegurar que tus relaciones M2M se comporten correctamente en staging y producción podemos ayudarte. Ofrecemos servicios cloud y migraciones a plataformas que incluyen validaciones post restore, por ejemplo para entornos en AWS y Azure consulta nuestros servicios cloud aws y azure y si tu proyecto necesita una solución personalizada en backend revisa nuestra oferta de software a medida y aplicaciones a medida.
También trabajamos en seguridad y detección proactiva de errores silenciosos como estos dentro de una estrategia más amplia de ciberseguridad, y ofrecemos servicios de inteligencia artificial para empresas, agentes IA y soluciones de inteligencia de negocio y power bi que complementan la observabilidad y el análisis de datos de tus aplicaciones. Palabras clave que reflejan nuestra experiencia: aplicaciones a medida, software a medida, inteligencia artificial, ciberseguridad, servicios cloud aws y azure, servicios inteligencia de negocio, ia para empresas, agentes IA y power bi.
Si quieres que revisemos tu proceso de backup y restore, implementemos scripts de reset de secuencias automatizados o integremos pruebas que validen relaciones M2M en tu pipeline de CI/CD, contacta con nosotros en Q2BSTUDIO. Evitar pequeñas inconsistencias ahora puede ahorrarte horas de debugging y mantener la confianza en tus despliegues.
Resumen final: tras restaurar una base de datos PostgreSQL, no basta con ajustar las secuencias de las tablas de modelos principales; hay que detectar y resetear también las secuencias de las tablas intermedias implícitas que Django crea para ManyToManyField. Hacerlo evita duplicados, IntegrityError y las temidas fallas silenciosas en relaciones M2M.