Describe objects storage

This commit is contained in:
Fred Pauchet 2024-03-20 18:42:47 +01:00
parent 873c8e610c
commit 58f9a56d67
11 changed files with 133 additions and 120 deletions

View File

@ -12,3 +12,70 @@ Il existe plusieurs manières de réaliser ceci ; le tout est de s'accorder sur
Heroku (((Heroku))) - que nous verrons au prochain chapitre - propose des espaces de déploiements, mais pas despace de stockage.
Il est possible dy envoyer des fichiers utilisateurs (typiquement, des media personnalisés), mais ceux-ci seront perdus lors du redémarrage du container.
Il est donc primordial de configurer correctement lhébergement des fichiers média, de préférences sur un stockage compatible S3 (((S3))).
=== Hébergement S3
Pour cette partie, nous allons nous baser sur
lhttps://www.scaleway.com/en/object-storage/[Object Storage de
Scaleway]. Ils offrent 75GB de stockage et de transfert par mois, ce qui
va nous laisser suffisament despace pour jouer un peu.
```bash
# requirements.txt
django==3.2.8
gunicorn
boto3
django-storages
```
image:deployment/scaleway-object-storage-bucket.png[align="center"]
Lidée est quau moment de la construction des fichiers statiques, Django aille simplement les héberger sur un espace de stockage compatible S3.
La complexité va être de configurer correctement les différents points de terminaison. Pour héberger nos fichiers sur notre *bucket* S3, il va falloir suivre et appliquer quelques étapes dans lordre :
. Configurer un bucket compatible S3 - je parlais de Scaleway, mais il y
en a - *littéralement* - des dizaines.
. Ajouter la librairie `boto3`, qui soccupera de dialoguer avec ce type de protocole
. Ajouter la librairie `django-storage`, qui va elle soccuper de
faire le câblage entre le fournisseur (*via* `+boto3+`) et Django, qui
sattend à ce quon lui donne un moteur de gestion *via* la clé https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-STATICFILES_STORAGE[DJANGO_STATICFILES_STORAGE].
La première étape consiste à se rendre dans https://console.scaleway.com/project/credentials[la console d'administration Scaleway], pour gérer
ses identifiants et créer un jeton.
image:deployment/scaleway-api-key.png[align="center"]
Selon la documentation de
https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings[django-storages], de
https://boto3.amazonaws.com/v1/documentation/api/latest/index.html[boto3]
et de https://www.scaleway.com/en/docs/tutorials/deploy-saas-application/[Scaleway], vous aurez besoin des clés suivantes au niveau du fichier
`settings.py` :
[source,python]
----
AWS_ACCESS_KEY_ID = os.getenv('ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME')
AWS_DEFAULT_ACL = 'public-read'
AWS_LOCATION = 'static'
AWS_S3_SIGNATURE_VERSION = 's3v4'
AWS_S3_HOST = 's3.%s.scw.cloud' % (AWS_S3_REGION_NAME,)
AWS_S3_ENDPOINT_URL = 'https://%s' % (AWS_S3_HOST, )
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3ManifestStaticStorage'
STATIC_URL = '%s/%s/' % (AWS_S3_ENDPOINT_URL, AWS_LOCATION)
# General optimization for faster delivery
AWS_IS_GZIPPED = True
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
----
[NOTE]
====
Idéalement et pour respecter nos 12-facteurs, tous ces paramètres devraient pouvoir être modifiés depuis les variables d'environnement.
====

View File

@ -0,0 +1,4 @@
\section{Kubernetes}\label{kubernetes}
Voir ici https://www.youtube.com/watch?v=NAOsLaB6Lfc ( La vidéo dure
5h\ldots)

View File

@ -125,8 +125,6 @@ régulier :
Europe/Brussels... done
....
(+ voir comment récupérer les backups)
....
# Copié/collé de https://cookiecutter- django.readthedocs.io/en/latest/deployment-on-heroku.html
heroku create --buildpack https://github.com/heroku/heroku-buildpack-python
@ -180,93 +178,20 @@ expliquera la commande pour le protocole WSGI.
=== Hébergement S3
....
# requirements.txt
django==3.2.8
gunicorn
boto3
django-storages
....
Au chapitre précédent, nous avons défini un ensemble de plusieurs variables pouvant être configurées.
Leur attribuer une valeur peut être réalisé depuis la console d'administration d'Heroku :
Pour cette partie, nous allons nous baser sur
lhttps://www.scaleway.com/en/object-storage/[Object Storage de
Scaleway]. Ils offrent 75GB de stockage et de transfert par mois, ce qui
va nous laisser suffisament despace pour jouer un peu.
image:images/deployment/scaleway-object-storage-bucket.png[image]
Lidée est quau moment de la construction des fichiers statiques,
Django aille simplement les héberger sur un espace de stockage
compatible S3. La complexité va être de configurer correctement les
différents points de terminaison. Pour héberger nos fichiers sur notre
*bucket* S3, il va falloir suivre et appliquer quelques étapes dans
lordre :
. Configurer un bucket compatible S3 - je parlais de Scaleway, mais il y
en a - *littéralement* - des dizaines.
. Ajouter la librairie `+boto3+`, qui soccupera de "parler" avec ce
type de protocole
. Ajouter la librairie `+django-storage+`, qui va elle soccuper de
faire le câblage entre le fournisseur (*via* `+boto3+`) et Django, qui
sattend à ce quon lui donne un moteur de gestion *via* la clé
[`+DJANGO_STATICFILES_STORAGE+`](https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-STATICFILES_STORAGE).
La première étape consiste à se rendre dans [la console
Scaleway](https://console.scaleway.com/project/credentials), pour gérer
ses identifiants et créer un jeton.
image:images/deployment/scaleway-api-key.png[image]
Selon la documentation de
https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings[django-storages],
de
https://boto3.amazonaws.com/v1/documentation/api/latest/index.html[boto3]
et de
https://www.scaleway.com/en/docs/tutorials/deploy-saas-application/[Scaleway],
vous aurez besoin des clés suivantes au niveau du fichier
`+settings.py+` :
[source,python]
----
AWS_ACCESS_KEY_ID = os.getenv('ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME')
AWS_DEFAULT_ACL = 'public-read'
AWS_LOCATION = 'static'
AWS_S3_SIGNATURE_VERSION = 's3v4'
AWS_S3_HOST = 's3.%s.scw.cloud' % (AWS_S3_REGION_NAME,)
AWS_S3_ENDPOINT_URL = 'https://%s' % (AWS_S3_HOST, )
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3ManifestStaticStorage'
STATIC_URL = '%s/%s/' % (AWS_S3_ENDPOINT_URL, AWS_LOCATION)
# General optimization for faster delivery
AWS_IS_GZIPPED = True
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
----
Cette partie pourrait éventuellement se trouver dans un fichier
`+heroku.py+`, que vous pourriez placer à côté de votre configuration
applicative. Le paramètre `+settings=+` pourrait alors pointer vers ce
nouveau fichier, pour ne pas polluer lenvironnement par défaut.
Configurez-les dans la console dadministration dHeroku:
image:images/deployment/heroku-vars-reveal.png[image]
image:deployment/heroku/vars-reveal.png[image]
Lors de la publication, vous devriez à présent avoir la sortie suivante,
qui sera confirmée par le *bucket*:
....
remote: -----> $ python manage.py collectstatic --noinput
remote: 128 static files copied, 156 post-processed
....
```bash
remote: -----> $ python manage.py collectstatic --noinput
remote: 128 static files copied, 156 post-processed
```
image:images/deployment/gwift-cloud-s3.png[image]
image:deployment/gwift-cloud-s3.png[image]
Sources complémentaires:

View File

@ -19,7 +19,7 @@ grand.
Conceptuellement, cest pourtant la manière de faire qui permettra davoir quelque chose à présenter très rapidement: à partir du moment où vous aurez un modèle de données, vous aurez accès, grâce à cet ORM à:
. Des migrations de données et la possibilité de faire évoluer votre modèle,
. Des migrations de données et la possibilité de faire évoluer votre modèle en corrélation avec votre couche de persistance,
. Une abstraction entre votre modélisation et la manière dont les données sont représentées _via_ un moteur de base de données relationnelles,
. Une interface dadministration auto-générée,
. Un mécanisme de formulaires HTML complet, pratique à utiliser, orienté objet et logique à faire évoluer,
@ -63,6 +63,8 @@ Si nous souhaitons ajouter une fonctionnalité permettant de calculer laire p
. Soit ajouter une classe de _visite_ qui ajoute cette fonction de calcul daire
. Soit modifier notre modèle pour que chaque structure hérite dune classe de type `Shape`, qui implémentera elle-même ce calcul daire.
==== Visitor
Dans le premier cas, nous pouvons procéder de la manière suivante:
[source,python]
@ -84,6 +86,8 @@ class Geometry:
----
==== Notions d'héritage
Dans le second cas, limplémentation pourrait évoluer de la manière suivante:
[source,python]

View File

@ -72,57 +72,47 @@ Les querysets vont cependant plus loin, et permettent de réaliser des :
==== Opérations logiques
Les opérat
....
Pour un `AND`, il suffit de chaîner les conditions. ** trouver un exemple ici ** :-)
....
....
Mais en gros : bidule.objects.filter(condition1, condition2)
....
....
Il existe deux autres options : combiner deux querysets avec l'opérateur `&` ou combiner des Q objects avec ce même opérateur.
....
Soit encore combiner des filtres:
Les opérations logiques "de base" sont accessibles très facilement et peuvent être chaînées de manière totalement séquentielle :
[source,python]
----
from core.models import Wish
Wish.objects
Wish.objects.filter(name__icontains="test").filter(name__icontains="too")
Book.filter(title__contains="a").filter(title__contains="b") <1>
Book.filter(title__contains="a", title__contains="b") <2>
----
<1> Ceci nous donnera d'abord les livres qui contiennent le caractère "a" dans leur titre, puis appliquera un deuxième filtre sur ceux qui contiennent *également* le caractère "b".
<2> Cette deuxième représentation est totalement identique à la première.
* Ca, cest notre manager.
* Et là, on chaîne les requêtes pour composer une recherche sur tous les
souhaits dont le nom contient (avec une casse insensible) la chaîne
"test" et dont le nom contient la chaîne "too".
Pour un OR, on a deux options :
. Soit passer par deux querysets, typiuqment `queryset1 queryset2`
. Soit passer par des `Q objects`, que lon trouve dans le namespace
`django.db.models`.
Une troisième option consiste à utiliser les `Q objects`, que nous pouvons trouver dans l'espace de noms `django.db`.
Ces éléments peuvent servir autant à appliquer un filtre `AND` que `OR` :
[source,python]
----
from django.db.models import Q
from django.db.models import Q
condition1 = Q(...)
condition2 = Q(...)
bidule.objects.filter(condition1 | condition2)
Book.objects.filter(
Q(title__contains="a"),
Q(title__contains="b")
) <1>
Book.objects.filter(
Q(title__contains="a") | Q(title__contains="b")
) <2>
----
<1> Nous cherchons les livres dont le titre contient "a" *ET* "b",
<2> Nous cherchons ici les livres dont le titre contient "a" *OU* "b"
Lopérateur inverse (_NOT_)
De la même manière, la négation peut être représentée _via_ un `Q object` sur lequel nous appliquerons l'opérateur `~` :
Idem que ci-dessus : soit on utilise la méthode `exclude` sur le
queryset, soit lopérateur `~` sur un Q object;
[source,python]
----
from django.db.models import Q
Book.objects.filter(~Q(title__contains="a")) <1>
----
<1> Nous cherchons ici les livres dont le titre *ne contient pas* le caractère "a".
[TIP]
====
Si on veut connaître la requête SQL sous-jacente à lexécution du queryset, il suffit dappeler la fonction `str()` sur la propriété `query`:

View File

@ -119,3 +119,5 @@ include::book/deployment/files-storage.adoc[]
include::book/deployment/paas.adoc[]
include::book/deployment/cloud-native.adoc[]
include::book/deployment/kubernetes.adoc[]

View File

@ -10,6 +10,19 @@ En restant dans les sentiers battus, votre projet suivra un patron de conception
Dans un pattern MVC classique, la traduction immédiate du contrôleur est une vue.
Et comme nous le verrons par la suite, la vue est en fait le template.
La principale différence avec un modèle MVC concerne le fait que la vue ne soccupe pas du routage des URLs ; ce point est réalisé par un autre composant, interne au framework, graĉe aux différentes routes définies dans les fichiers `urls.py`.
A part ce point, le pattern MVC cite:[design_patterns(520)] est respecté sous réserve de suivre ces correspondances :
[cols="1,1"]
|===
|Model
|`models.py`
|View
|Template
|Controler
|`views.py`
|===
* Le *modèle* (que l'on retrouvera souvent dans le module `models.py`) fait le lien avec la base de données et permet de définir les champs et leur type à associer à une table. Grosso modo, une table SQL correspondra à une classe dun modèle Django.
* La *vue* (`views.py`), qui joue le rôle de contrôleur : a priori, tous les traitements, la récupération des données, etc. doit passer par ce composant et ne doit (pratiquement) pas être généré à la volée, directement à laffichage dune page. En dautres mots, la vue sert de pont entre les données gérées par la base et linterface utilisateur.

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -99,6 +99,14 @@
year = {2015},
publisher = {Packt Publishing}
}
@book{design_patterns,
title = {Head First Design Patterns},
booktitle = {Building Extensible & Maintainable Object-Oriented Software},
edition = {2nd edition},
year = {2020},
publisher = {O'Reilly Media, Inc.},
isbn = {9781492078005}
}
@book{unix_philosophy,
author = {Eric S. Raymond},
year = {2004},