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

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.
  1. 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

  1. Création du projet Django (12s)

$ django-admin startproject appclient
  1. 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)

  1. 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
  1. 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)

  1. 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 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

  1. 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 :

  • http://localhost:8000/api/client : liste des clients de la base
  • http://localhost:8000/api/client/[ID] : données d’un client

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