• Mémo Convertir une clef étrangère en champ ManytoManyField

  • Changement des relations dans un SGBD

Toucher à une base de données peut être périlleux. Pour modifier une Foreign Key en ManyToManyField, j'ai suivi ce tutoriel.

Nous avons le modèle suivant :

from django.db import models


class Author(models.Model):
    name = models.CharField(max_length=20)


class Book(models.Model):
    name = models.CharField(max_length=20)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

Lancement de la migration (où 'library' est le nom de l'application):

python3 manage.py makemigrations library
python3 manage.py migrate

Après avoir rempli consciencieusement la base de données, éclair de génie : un livre peut avoir plusieurs auteurs (Lagarde & Michard, Bernstein & Milza...). Il va donc falloir reprendre la base de données sans trop lui taper dessus. Pour cela, il faut redéfinir la table. Il faudra amender le premier champ avec related name et ajouter une relation plusieurs à plusieurs.

class Book(models.Model):
    name = models.CharField(max_length=20)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, old author)
    authors = models.ManyToManyField(Author)

Pour repeupler la base de données, on lance une première migration, puis on crée un document modifiable :

python3 manage.py makemigrations library
python3 manage.py makemigrations library --empty

On y crée une fonction qui va importer les données du premier champ à celui nouvellement créé :

from django.db import migrations

def forward(apps, schema_editor):
    Book = apps.get_model("library", "Book")
    for book in Book.objects.all():
        book.authors.add(website.author)

class Migration(migrations.Migration):

    dependencies = [
        ('library', '0003_auto_20181122_1454'),
    ]

    operations = [
        migrations.RunPython(forward)
    ]

On relance la migration et on vérifie dans l'interface admin que les modifications ont bien été faites :

python3 manage.py migrate

Si oui, alors il est possible de supprimer le champ "author" devenu obsolète, et de refaire une migration :

python3 makemigrations appname
python3 migrate

Les requêtes vouées à gérer ces champs doivent aussi être changées, ce qui fera l'objet d'un autre post en temps voulu !


24 décembre 2018 10:57