Bonjour,
Pour une application métier libre de collecte de données naturalistes pour l’étude des chauves-souris (http://www.dbchiro.org), j’ai besoin de pouvoir proposer une vue permettant d’importer des fichiers issues de tableurs (csv propres) dans la base de données. Pour importer ces données dans une table unique, pas de soucis, plusieurs extensions existent (django-import-export ou django-csvimport notamment). Par contre, mon besoin est plus particulier car ma donnée naturaliste est répartie en plusieurs tables distinctes (sans compter les tables de dictionnaires).
Voici le schéma de principe :
- Model Localités (Place) (une localité est un site avec des coordonnées x/y unique comme un bâtiment).
- 1-n Model Sessions (Session) (une donnée = une date et une méthode d’inventaire par localité)
- 1-n Model Observations (Sighting) (une donnée = une espèce par session)
- 1-n Model Observation détaillée (CountDetail) (une donnée = 1 détail précis d’une espèce: ex: nombre de mâles, nombre de femelles, etc.)
- 1-n Model Observations (Sighting) (une donnée = une espèce par session)
- 1-n Model Sessions (Session) (une donnée = une date et une méthode d’inventaire par localité)
Ce que j’aimerai obtenir, c’est la possibilité d’importer les données d’une session avec un seul fichier csv qui permettrait de peupler les deux derniers modèles: Observations (Sighting) et pour chaque observation (chaque espèce observée), ses données détaillées (CountDetail).
Existe-t-il une ou des solutions simples (je me débrouille mais je ne suis pas non plus un grand expert du python).
Sinon, la solution à laquelle je pensais serait d’importer ces données en cache ou dans un modèle spécifique (correspondance parfaite à ce CSV) et à chaque import, d’éxécuter des requêtes pour peupler les tables: 1. Import du fichier source (CSV, ods, excel) par formulaire. 2. Création et insertion du lot de données dans la table parente avec la commande un "select distinct" sur les champs correspondants au modèle observation (espèce). 3. Puis pour chaque espèce de la session (for…), création et insertion des données dans la table enfant (CoutDetail).
Je suis preneur de conseils/exemples/snippets
Merci!
Fred.
Voici un extrait de mon fichier models.py (fichier complet sur Framagit):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | class Place(models.Model): id_place = models.AutoField(primary_key=True, db_index=True) [...] class Meta: verbose_name = "Localité" unique_together = ['name', 'municipality', 'type'] class Session(models.Model): id_session = models.AutoField(primary_key=True) contact = models.ForeignKey(Contact,models.DO_NOTHING, null=True, verbose_name=_("Type de contact")) place = models.ForeignKey(Place,on_delete=models.CASCADE,verbose_name='Localité associée') date_start = models.DateField( verbose_name='Date de début', help_text=_('Format de date: <em>01/01/2017</em>.')) [...] timestamp_create = models.DateTimeField( auto_now_add=True, editable=False) timestamp_update = models.DateTimeField( auto_now=True, editable=False) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='session_creator') updated_by = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='session_modifier') def __str__(self): return "%s ∙ %s ∙ %s" % ( self.place, datetime.date(self.date_start.year, self.date_start.month, self.date_start.day), self.contact) class Meta: verbose_name = "Session d'inventaire/observations" unique_together = ["place", "contact", "date_start"] class Sighting(models.Model): id_sighting = models.AutoField(_('id unique'), primary_key=True) session = models.ForeignKey( Session, on_delete=models.CASCADE, verbose_name=_('Session associée')) period = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('Période d\'observation')) codesp = models.ForeignKey( Specie, on_delete=DO_NOTHING, verbose_name=_('Espèce ou groupe d\'espèce')) total_count = models.PositiveIntegerField('Nombre total', blank=True, null=True, help_text=_('Désactivé pour les données acoustiques et en main')) breed_colo = models.NullBooleanField( verbose_name='Colonie de reproduction') [...] timestamp_create = models.DateTimeField( auto_now_add=True, editable=False) timestamp_update = models.DateTimeField( auto_now=True, editable=False) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='sighting_creator') updated_by = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='sighting_modifier') def __str__(self): return "%s ∙ %s ∙ %s" % (self.session, self.codesp, self.total_count) class Meta: verbose_name = "Observation" verbose_name_plural = "Observations" unique_together = ["codesp", "session"] class CountDetail(models.Model): id_countdetail = models.AutoField(primary_key=True) sighting = models.ForeignKey(Sighting, on_delete=models.CASCADE, related_name='countdetail_sighting') method = models.ForeignKey(Method, on_delete=models.DO_NOTHING, verbose_name=_('Méthode'), blank=True, null=True) sex = models.ForeignKey(Sex,models.DO_NOTHING,blank=True,null=True,verbose_name=_('Sexe')) age = models.ForeignKey(Age,models.DO_NOTHING,blank=True,null=True,verbose_name=_('Age estimé')) [...] timestamp_create = models.DateTimeField( auto_now_add=True, editable=False) timestamp_update = models.DateTimeField( auto_now=True, editable=False) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='countdetail_creator') updated_by = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='countdetail_modifier') def __str__(self): return "%s ∙ %s ∙ %s ∙ %s" % (self.sighting.session.place.name, self.sex, self.age, self.count) class Meta: verbose_name = "4 ∙ Comptage détaillé" |