• 4.2
  • 5.1
  • dev
  • Version de la documentation : 5.0

Instantanés

Qu’est-ce qu’un instantané (fixture en anglais) ?

Un instantané est un ensemble de fichiers contenant du contenu sérialisé de base de données. Chaque instantané possède un nom unique et les fichiers composant l’instantané peuvent être distribués dans plusieurs répertoires et plusieurs applications.

Comment produire un instantané

Les instantanés peuvent être générés par la commande manage.py dumpdata. Il est aussi possible de produire des instantanés personnalisés en utilisant directement les outils de sérialisation ou même en les écrivant à la main.

Comment utiliser un instantané

Les instantanés peuvent être utilisés pour préremplir la base de données avec des données pour les tests:

class MyTestCase(TestCase):
    fixtures = ["fixture-label"]

ou pour fournir des données initiales en utilisant la commande loaddata:

django-admin loaddata <fixture label>

Emplacements de recherche des instantanés

Django recherche les instantanés à ces emplacements :

  1. Dans le répertoire fixtures de chaque application installée
  2. Dans tout répertoire mentionné dans le réglage FIXTURE_DIRS
  3. Dans le chemin explicitement contenu dans le nom de l’instantané

Django va charger tous les instantanés qu’il trouve aux emplacements indiqués par les noms d’instantanés. Si un nom d’instantané indiqué possède une extension de fichier, seuls des instantanés de ce type seront chargés. Par exemple :

django-admin loaddata mydata.json

ne charge que les instantanés JSON nommés mydata. L’extension d’instantané doit correspondre au nom enregistré d’un sérialiseur (par ex. json ou xml).

Si vous omettez l’extension, Django recherche tous les types d’instantané disponibles pour chaque instantané trouvé. Par exemple :

django-admin loaddata mydata

recherche tout instantané ou type d’instantané nommé mydata. Si un répertoire d’instantané contient mydata.json, cet instantané serait chargé comme instantané JSON.

Les noms d’instantanés peuvent contenir une partie « chemin ». Ces répertoires sont alors inclus dans le chemin de recherche. Par exemple :

django-admin loaddata foo/bar/mydata.json

recherche <étiquette_app>/fixtures/foo/bar/mydata.json pour chaque application installée, <nom_rép>/foo/bar/mydata.json pour chaque répertoire dans FIXTURE_DIRS ainsi que le chemin littéral foo/bar/mydata.json.

Ordre de chargement des instantanés

Plusieurs instantanés peuvent être indiqués dans la même invocation. Par exemple :

django-admin loaddata mammals birds insects

ou dans une classe de cas de tests :

class AnimalTestCase(TestCase):
    fixtures = ["mammals", "birds", "insects"]

L’ordre dans lequel sont chargés les instantanés suit l’ordre dans lequel ils sont indiqués, que ce soit lors de l’utilisation de la commande d’administration ou quand ils sont mentionnés dans une classe de cas de tests comme démontré plus haut.

Dans ces exemples, tous les instantanés nommés mammals dans toutes les applications (dans l’ordre d’apparition des applications dans INSTALLED_APPS) seront chargés en premier. Puis, tous les instantanés birds seront chargés, suivis par tous les instantanés insects.

Sachez que si le moteur de base de données gère les contraintes de lignes, celles-ci seront vérifiées à la fin de la transaction. Toute relation traversant les instantanés peut aboutir à une erreur de chargement si la configuration de base de données ne prend pas en charge le contrôle différé des contraintes (référez-vous à la documentation de MySQL pour un exemple).

Comment les instantanés sont enregistrés en base de données

Lorsque des fichiers d’instantanés sont traités, les données sont enregistrées telles quelles dans la base de données. Les méthodes save() définies dans les modèles ne sont pas appelées et les éventuels signaux pre_save ou post_save sont appelés avec raw=True car l’instance ne contient que les attributs locaux du modèle. Il est par exemple imaginable de désactiver les gestionnaires accédant aux champs liés absents lors du chargement des instantanés, car une exception serait générée dans le cas contraire :

from django.db.models.signals import post_save
from .models import MyModel


def my_handler(**kwargs):
    # disable the handler during fixture loading
    if kwargs["raw"]:
        return
    ...


post_save.connect(my_handler, sender=MyModel)

On pourrait aussi écrire un décorateur pour encapsuler cette logique :

from functools import wraps


def disable_for_loaddata(signal_handler):
    """
    Decorator that turns off signal handlers when loading fixture data.
    """

    @wraps(signal_handler)
    def wrapper(*args, **kwargs):
        if kwargs["raw"]:
            return
        signal_handler(*args, **kwargs)

    return wrapper


@disable_for_loaddata
def my_handler(**kwargs): ...

Il faut cependant être conscient que cette logique désactivera les signaux lors de chaque désérialisation des instantanés, pas seulement durant loaddata.

Instantanés compressés

Les instantanés peuvent être compressés dans les formats zip, gz, bz2, lzma ou xz. Par exemple :

django-admin loaddata mydata.json

recherche l’un des fichiers mydata.json, mydata.json.zip, mydata.json.gz, mydata.json.bz2, mydata.json.lzma ou mydata.json.xz. Le premier fichier contenu dans une archive compressée est utilisé.

Notez que si deux instantanés de même nom mais de type différent sont trouvés (par exemple si mydata.json et mydata.xml.gz sont trouvés dans le même répertoire d’instantanés), l’installation des instantanés est interrompue et toute donnée déjà installée par l’appel à loaddata est retirée de la base de données.

MySQL avec MyISAM et les instantanés

Le moteur de stockage MyISAM de MySQL ne gère ni les transactions, ni les contraintes. Si vous utilisez ce moteur, les données d’instantanés ne sont pas validées et d’éventuelles données déjà chargées en base de données ne sont pas effacées dans le cas où des fichiers d’instantanés conflictuels sont trouvés.

Instantanés spécifiques à certaines bases de données

Si vous vous trouvez dans une configuration avec plusieurs bases de données, il se pourrait que vous vouliez charger certains instantanés dans une base de données mais pas dans l’autre. Dans cette situation, vous pouvez insérer des identifiants de base de données dans les noms des instantanés.

Par exemple, si votre réglage DATABASES contient une base de données users, nommez l’instantané mesdonnees.users.json ou mesdonnees.users.json.gz et cet instantané ne sera chargé que lorsque vous indiquez que vous souhaitez charger des données dans la base de données users.

Back to Top