BLOGS

Import de CSV + un backoffice + un service REST en ...... moins de 20mn

Importer des données CSV, pour ensuite les manipuler avcec un backoffice, et les remettre à disposition via une API c’est possible ?

Nous avons un fichier avec le format :

    UID;Raison_social;code_client;email;telephone;fax;adresse;code_postal;ville
    1;raisoc1;code1;email1;tel1;fax1;adresse1;postal1;ville1
    2;raisoc2;code2;email2;tel2;fax2;adresse2;postal2;ville2
    3;raisoc3;code3;email3;tel3;fax3;adresse3;postal3;ville3
    4;raisoc4;code4;email4;tel4;fax4;adresse4;postal4;ville4
    5;raisoc5;code5;email5;tel5;fax5;adresse5;postal5;ville5
    6;raisoc6;code6;email6;tel6;fax6;adresse6;postal6;ville6

On est d’accord le fichier est bizarre mais c’est souvent le propre des fichiers de données ;-)

Notre choix technique : Django (ben oui, faut aller vite)

Bon, c’est parti, chronomètre en main : 3 …. 2 …. 1 ….. GO

1) Création de l’environnement de travail (10s)

    $mkvirtualenv appclient
    New python executable in appclient/bin/python
    Installing setuptools, pip...done.

2) Installation de Django et extensions nécessaires (2mn15s)

    pip install Django==1.7
    pip install ipython
    pip install django-extensions
    pip install django-debug-toolbar
    pip install django-adaptors
    pip install django-suit
    pip install djangorestframework
    pip install django-filter
    pip install markdown

Certaines choses ne sont pas utiles (ipython, suit) mais suit permettra d’avoir un backoffice sympa, et ipython ça aide

3) Création du projet Django (12s)

    $ django-admin startproject appclient

4) Configuration des extensions (1mn3s)

On édite le fichier settings.py du répertoire appclient

    TEMPLATE_CONTEXT_PROCESSORS = TCP + (
        'django.core.context_processors.request',
    )
    # Application definition
    
    INSTALLED_APPS = (
        'suit',
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'debug_toolbar.apps.DebugToolbarConfig',
        'rest_framework',
        'django_extensions',
    
    )

On lance quand même un manage pour vérifier que cela marche toujours

On a laissé la conf par défaut pour le reste (on utilise une base sqlite)

5) Création du modèle de données (2mn47)

Pour faire les choses sympa, on va utiliser dia pour faire un diagramme uml en utilisant les libellés du fichier CSV comme nom d’attributs

Cela donne (pour le fichier client.dia):

model sous dia

Ensuite, on lance :

    ./manage.py create_app --diagram=client.dia client

Et il faut modifier le fichier admin.py du répertoire appclient/client, car django-extensions génère un fichier admin.py avec une erreur.

Il faut remplacer

    from appclient.client.models import Client

par

    from .models import Client

6) Création de la base, des tables, et l’utilisateur admin (1mn10)

On utilise les commandes manage suivantes :

    ./manage.py migrate
    ./manage.py createsuperuser
    ./manage runserver

Ce qui donne sur ma console

    (appclient)[cbrun@localhost appclient]$ ./manage.py migrate
    Operations to perform:
      Synchronize unmigrated apps: rest_framework, django_extensions, debug_toolbar, client, suit
      Apply all migrations: admin, contenttypes, auth, sessions
    Synchronizing apps without migrations:
      Creating tables...
        Creating table client_client
      Installing custom SQL...
      Installing indexes...
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying sessions.0001_initial... OK
    (appclient)[cbrun@localhost appclient]$ ./manage.py createsuperuser
    Username (leave blank to use 'cbrun'): admin
    Email address: christophe.brun.cl194@gadz.org
    Password: 
    Password (again): 
    Superuser created successfully.
    (appclient)[cbrun@localhost appclient]$ ./manage.py runserver
    Performing system checks...
    System check identified no issues (0 silenced).
    October 08, 2014 - 20:53:27
    Django version 1.7, using settings 'appclient.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CONTROL-C.

Et là, on peut se connecter au backoffice en admin sur http://localhost:8000/admin et on a une super interface d’admin (merci django-suit)

7) Bon on importe ???? (3mn8s import compris)

On édite le fichier client/models.py pour ajouter le modèle pour l’import

    from django.db import models
    from adaptor.model import CsvDbModel
    class Client(models.Model) :
        UID = models.IntegerField()
        Raison_social = models.CharField(max_length=20)
        code_client = models.CharField(max_length=10)
        email = models.CharField(max_length=100, blank=True, null=True )
        telephone = models.CharField(max_length=12, blank=True, null=True )
        fax = models.CharField(max_length=12, blank=True, null=True )
        adresse = models.CharField(max_length=20, blank=True, null=True )
        code_postal = models.CharField(max_length=6, blank=True, null=True )
        ville = models.CharField(max_length=50, blank=True, null=True )
    
        def __str__(self):
            return self.Raison_social
    
    class ClientCsvModel(CsvDbModel):
        class Meta:
            dbModel = Client
            delimiter = ";"
            has_header = True

On a fait l’import d’adaptor, ensuite, on a profiter de l’occasion pour ajouter la fonction \__str__ à la classe client (c’est pour avoir un nom pertinent dans les listes en backoffice) et on ajoute une classe ClientCsvModel.

Bien sûr, dans notre exemple le mapping des champs est évident, dans le cas contraire, il faut spécifier la liste des champs.

On donne le delimiter, et on indique que la première ligne contient les libellés

On lance la console (en utilisant shell_plus qui vient de django-extensions et qui a pour avantage de charger nos modèles) et on lance les commande

    In [1]: from client.models import ClientCsvModel
    In [2]: ClientCsvModel.import_data(data=open("../fichier_import.csv"))

Et normalement, ça importe (allez voir en backoffice).

On tient le bon bout, on a une application, un backoffice et nos données sont importées.

Ah, oui, reste le webservice

8) RESTez, il y a le RESTe à faire (4mn34s)

On commence par créer dans l’app client un serializer pour le model. On édite le fichier client/serializers.py :

    from .models import Client
    from rest_framework import serializers
    class ClientSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = Client

Ensuite, rest_framework a besoins d’une vue, donc on édite le fichier views.py (client/views.py):

    from .models import Client
    from rest_framework import viewsets
    from .serializers import ClientSerializer
    class ClientViewSet(viewsets.ModelViewSet):
        queryset = Client.objects.all()
        serializer_class = ClientSerializer

Enfin, on branche notre webservice, en éditant le fichier urls.py (du projet, soit appclient/urls.py)

    from django.conf.urls import patterns, include, url
    from django.contrib import admin
    from rest_framework import routers
    from client import views
    router = routers.DefaultRouter()
    router.register(r'client', views.ClientViewSet)
    urlpatterns = patterns('',
       # Examples:
       # url(r'^$', 'appclient.views.home', name='home'),
       # url(r'^blog/', include('blog.urls')),
    
       url(r'^admin/', include(admin.site.urls)),
       url(r'^api/',include(router.urls)),
    )

Si notre server est toujours actifs (on le relance dans le cas contraire) et si tout est ok, on peut appeler l’api par http://localhost:8000/api pour avoir une interface de consultation et valider le webservice.

Nos données sont accessibles par :

ET voilà, je m’arrête là, en 8 étapes et moins de 20mn (un peu plus de 15mn, il reste 4mn pour livrer ;-) )

Ok, il reste des choses à faire, c’est brut, mais les principes sont là.

Dans les choses à faire pour terminer par exemple :

  • il faut livrer
  • contrôle des données
  • faire une commande pour l’import (plutôt que d’utiliser le shell django)
  • faire des tests, de la doc
  • Et voilà, c’est fini
comments powered by Disqus