Django & DRF 101, initialisation de l'environnement : virtualenv & docker
Tags: django, drf, djangorestframework, installation
Published: 2020-02-19 17:13:01

---
title: Django & DRF 101, initialisation de l'environnement : virtualenv & docker
published: true
description: Initialisation d'un environnement pour django / drf
tags: django, drf, djangorestframework, installation
series: Django DRF
---

# Note Bene

Dans la suite de l'article, le serveur d'application Web django pourra fonctionner selon le type d'environnement :

* http://localhost:8000 dans le cas du virtualenv
* http://plateform dans le cas de containers Docker

# Environnement django sur un poste de développement

  * [avec virtualenv](#virtualenv)
  * [avec docker](#docker)


Dans cet article, je vais axer sur l'installation de Django et de modules sur un poste de développement, en local, via virtualenv et docker.

On se basera sur la version 3.0.6 de django et la 3.11.x de DRF et quelques modules utiles. 


> <mark>**[EDIT]**</mark> Le billet se basait initialement sur une version django 2.2.11, pour passer en django 3.0, des modules ont dû être modifiés car plus maintenus : django-rest-swagger => [drf-yasg](https://drf-yasg.readthedocs.io/en/stable/) (le __staticfiles__ utilisé sur django-rest-swagger n'est plus valable en django 3.0 voir [les modules retirés en 3.0](https://docs.djangoproject.com/en/dev/releases/3.0/#features-removed-in-3-0) ou la réponse {% stackoverflow 55929473 %}
 djangorestframework-jwt => [drf-jwt](https://styria-digital.github.io/django-rest-framework-jwt/) (il y a aussi [simplejwt](https://django-rest-framework-simplejwt.readthedocs.io/en/latest/) mais drf-jwt permet l'[__impersonnalisation__](https://styria-digital.github.io/django-rest-framework-jwt/#impersonation-token) que nous verrons dans un article ultérieur)

Le répertoire de travail est **projet**

le <a name="requirements">requirements.txt</a> utilisé dans les 2 méthodes 

```
django==3.0.4
djangorestframework==3.11.0
drf-jwt==1.15.1
django-filter==2.2.0
django-cors-headers==3.2.1
coreapi==2.3.3
coreapi-cli==1.0.9
requests==2.20.0
django-extensions==2.2.9
django-debug-toolbar==2.2
drf-yasg==1.17.1
```

## virtualenv <a name="virtualenv"></a>


En utilisant [virtualenv](https://virtualenv.pypa.io/en/latest/).

Dans un nouveau répertoire :

$ mkdir projet && cd projet

Le nom `env`, derrière virtualenv, est arbitraire, c'est le nom de l'environnement virtuel, cela pourrait être `myenv`, `projet_truc`, etc

$ virtualenv env

$ source vend/bin/activate 

ou sous Windows : 

$ source env/Scripts/activate 

pour désactiver l'environnement virtuel : $ deactivate

Installation des packages à la main :

$ pip install django==3.0.4
$ pip install djangorestframework==3.11.0
$ pip install django-filter==2.1.0
$ ...

ou par un fichier **requirements.txt** qui contient les packages que l'on souhaite installer pour les utiliser par la suite

```
$ pip install -r requirements.txt
```

L'environnement est prêt, un 

```
$ python manage.py runserver
```

permet de lancer le serveur sur le port 8000 (http://127.0.0.1:8000/)


## docker <a name="docker"></a>


A mon sens, c'est le plus adapté en équipe, l'objectif étant d'élaborer des images qui peuvent être partagées au sein de différentes stations de travail, l'environnement sera uniforme pour tous :

- du frontal (nginx)
- du serveur d'applications (django et des modules) et "monter" les sources dedans pour l'exécuter
- si on utilise un SGBD (Postgresql par exemple), un containeur postgresql

Une requête HTTP suivra le chemin suivant : navigateur --> nginx --> django

```
$ mkdir projet && cd projet
$ mkdir docker && cd docker
```

A partir du répertoire docker, on aura les fichiers suivants, à créer

```
$ find .
.
./build.sh
./docker-compose.yml
./Dockerfile
./nginx
./nginx/conf.d
./nginx/conf.d/plateform.conf
./requirements.txt
```

- créer l'image : exécute la commande **docker build** avec comme source le fichier Dockerfile qui contient les instructions de création de l'image django.

Source du **Dockerfile**, basé sur une image python 3.7, le port exposé à partir du container sera le 8100

```yaml
FROM python:3.7-slim-buster
RUN apt-get clean
RUN apt-get update
RUN apt-get install -y libsasl2-dev python-dev libldap2-dev libssl-dev \
    libfontconfig1 libxrender1 unzip \
    libfreetype6 libc6 zlib1g libpng-dev\
    libxtst6 libtiff5-dev libjpeg62-turbo-dev zlib1g-dev libfreetype6-dev fontconfig libxml2-dev libxslt1-dev gettext \
    libaio1 libaio-dev build-essential \
     && mkdir /code && mkdir /static 
RUN apt-get clean
ENV PYTHONIOENCODING=UTF-8
WORKDIR /code
COPY ./requirements.txt requirements.txt
RUN pip install --upgrade pip && pip install -r requirements.txt
RUN apt-get install -y python3-lxml python3-cffi libcairo2 libpango1.0-0 libgdk-pixbuf2.0-0 libffi-dev shared-mime-info libcairo2 && apt-get -y clean
ADD . /code
ENV TZ=Europe/Paris
RUN apt-get update && apt-get install -y cron
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
```

le fichier **build.sh**: crée à partir du Dockerfile une image api-plateform:latest

```bash
#!/usr/bin/env bash
docker build -f Dockerfile -t api-plateform:latest .
```


```
$ ./build.sh
```

L'image est créée

```
$ docker image ls -a |grep api-pla
api-plateform                                  latest                 bda692c67a29        27 hours ago        782MB

```

- ajouter à votre **hosts** un alias __plateform__

```
127.0.0.1       localhost  plateform
```

- démarrer les containers grâce au **docker-compose.yml** qui décrit les services  (container) à démarrer

Le **docker-compose.yml** qui sert au démarrage des différents containeurs : nginx, le serveur d'applications django :
 
```yaml
version: '3.1'
services:
  api-plateform:
    image: api-plateform:latest
    container_name: api-plateform
    command: python3 manage.py runserver 0.0.0.0:8110
    volumes:
    - ../backend:/code
    networks:
    - api-plateform

  nginx-plateform:
    image: nginx
    container_name: nginx-plateform
    restart: "no"
    depends_on:
      - api-plateform
    ports:
     - 80:80
    networks:
     - api-plateform
    volumes:
     - ./nginx/conf.d/plateform.conf:/etc/nginx/conf.d/plateform.conf
     - ../log/:/var/log/nginx/

networks:
  api-plateform:
```

le fichier de configuration NGINX qui permet de __natter__ le 8100 du containeur vers le port 80 pour l'extérieur, fichier nginx/conf.d/plateform.conf

```
server {
    listen 80;
    server_name plateform;
    error_log /var/log/nginx/error.log;

    access_log /var/log/nginx/access.log;
    client_body_buffer_size 10m;
    client_max_body_size 10m;
    client_body_timeout 120s;

    location / {
         proxy_pass http://api-plateform:8110/;
         proxy_redirect     off;
         proxy_set_header   Host             $host;
         proxy_set_header   X-Real-IP        $remote_addr;
         proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
         proxy_set_header   X-Forwarded-Protocol "http";
    }
}
```

```
$ docker-compose up
Creating network "docker_api-plateform" with the default driver
Creating api-plateform ... done
Creating nginx-plateform ... done
Attaching to api-plateform, nginx-plateform
api-plateform      | Watching for file changes with StatReloader
```

Le site est accessible par http://plateform