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.