through relations queryset one many example django django-models django-migrations

queryset - one to one relations django



MigraciĆ³n de datos de Django al cambiar un campo a ManyToMany (2)

Me doy cuenta de que esta pregunta es antigua y, en ese momento, la mejor opción para Data Migrations era usar South. Ahora Django tiene su propio comando de migrate , y el proceso es ligeramente diferente.

He agregado estos modelos a una aplicación llamada books ; ajuste en consecuencia si ese no es su caso.

Primero, agregue el campo a Book y un related_name a al menos uno, o ambos (o related_name en conflicto):

class Book(models.Model): author = models.ForeignKey(Author, related_name=''book'') authors = models.ManyToManyField(Author, related_name=''books'') title = models.CharField(max_length=100)

Generar la migración:

$ ./manage.py makemigrations Migrations for ''books'': 0002_auto_20151222_1457.py: - Add field authors to book - Alter field author on book

Ahora, cree una migración vacía para mantener la migración de los datos en sí:

./manage.py makemigrations books --empty Migrations for ''books'': 0003_auto_20151222_1459.py:

Y añádale el siguiente contenido. Para comprender exactamente cómo funciona esto, consulte la documentación sobre Migraciones de datos . Tenga cuidado de no sobrescribir la dependencia de migración.

# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations def make_many_authors(apps, schema_editor): """ Adds the Author object in Book.author to the many-to-many relationship in Book.authors """ Book = apps.get_model(''books'', ''Book'') for book in Book.objects.all(): book.authors.add(book.author) class Migration(migrations.Migration): dependencies = [ (''books'', ''0002_auto_20151222_1457''), ] operations = [ migrations.RunPython(make_many_authors), ]

Ahora elimine el campo del author del Modelo: debería verse así:

class Book(models.Model): authors = models.ManyToManyField(Author, related_name=''books'') title = models.CharField(max_length=100)

Cree una nueva migración para eso y ejecútelos todos:

$ ./manage.py makemigrations Migrations for ''books'': 0004_remove_book_author.py: - Remove field author from book $ ./manage.py migrate Operations to perform: Synchronize unmigrated apps: messages, staticfiles Apply all migrations: admin, auth, sessions, books, contenttypes Synchronizing apps without migrations: Creating tables... Running deferred SQL... Installing custom SQL... Running migrations: Rendering model states... DONE Applying books.0002_auto_20151222_1457... OK Applying books.0003_auto_20151222_1459... OK Applying books.0004_remove_book_author... OK

Y eso es. Los autores previamente disponibles en book.author ahora deben estar en el conjunto de preguntas que obtienes de book.authors.all() .

Tengo una aplicación Django en la que quiero cambiar un campo de ForeignKey a ManyToManyField. Quiero preservar mi información anterior. ¿Cuál es el proceso más simple / mejor a seguir para esto? Si es importante, uso sqlite3 como mi back-end de base de datos.

Si mi resumen del problema no está claro, aquí hay un ejemplo. Digamos que tengo dos modelos:

class Author(models.Model): author = models.CharField(max_length=100) class Book(models.Model): author = models.ForeignKey(Author) title = models.CharField(max_length=100)

Digamos que tengo muchos datos en mi base de datos. Ahora, quiero cambiar el modelo de Libro de la siguiente manera:

class Book(models.Model): author = models.ManyToManyField(Author) title = models.CharField(max_length=100)

No quiero "perder" todos mis datos anteriores.

¿Cuál es la mejor / más simple forma de lograr esto?

Conocido


Probablemente lo mejor y más fácil que debe hacer sería:

Cree el campo Muchos a muchos con un nombre diferente.

authors = models.ManyToManyField(Author)

escriba una pequeña función para convertir valores de clave externa a valores M2M:

def convert(): books = Book.objects.all() for book in books: if book.author: li = [book.author.id] book.authors.append(li) book.save()

Una vez que se ejecuta, puede eliminar el campo de autor de la tabla y ejecutar la migración nuevamente.