Comment écrire une application Django installable – Real Python

By | mai 27, 2020

Cours Python en ligne

Dans le cadre de Django, un projet fait référence à la collection de fichiers de configuration et de code pour un site Web particulier. Django regroupe la logique métier dans ce qu'elle appelle applications, qui sont les modules du framework Django. Il y a beaucoup de documentation sur la façon de structurer vos projets et les applications qu'ils contiennent, mais quand vient le temps de conditionner une application Django installable, les informations sont plus difficiles à trouver.

Dans ce didacticiel, vous allez apprendre à retirer une application d'un projet Django et à l'empaqueter pour qu'elle soit installable. Une fois que vous avez emballé votre application, vous pouvez la partager sur PyPI afin que d'autres puissent la récupérer installer pip.

Assurez-vous de suivre les exemples en téléchargeant le code source sur le lien ci-dessous:

Conditions préalables

Ce tutoriel nécessite une certaine familiarité avec Django, pépin, PyPI, pyenv (ou un outil d'environnement virtuel équivalent), et tox. Pour en savoir plus sur ces sujets, consultez:

Démarrage d'un exemple d'application Django dans un projet

Ce didacticiel comprend un package de travail pour vous guider dans le processus de création d'une application Django installable. Vous pouvez télécharger le code source sur le lien ci-dessous:

Même si vous avez initialement l'intention de rendre votre application Django disponible sous forme de package, vous êtes susceptible de commencer à l'intérieur d'un projet. Pour illustrer le processus de passage d'un projet Django à une application Django installable, j'ai mis à disposition deux branches dans le référentiel. le branche de projet est l'état de départ d'une application à l'intérieur d'un projet Django. le branche principale est l'application installable terminée.

Vous pouvez également télécharger l'application terminée sur la page du package PyPI realpython-django-receipts. Vous pouvez installer le package en exécutant pip installe realpython-django-receipts.

L'exemple d'application est une courte représentation des éléments de ligne sur un reçu. Dans la branche du projet, vous trouverez un répertoire nommé sample_project qui contient un projet Django fonctionnel. Le répertoire ressemble à ceci:

sample_project /
│
├── reçus /
│ ├── luminaires /
│ │ └── receipts.json
│ │
│ ├── migrations /
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ │
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
│
├── sample_project /
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
├── db.sqlite3
├── manage.py
├── resetdb.sh
└── runserver.sh

La version la plus récente de Django au moment où ce tutoriel a été écrit était 3.0.4, et tous les tests ont été effectués avec Python 3.7. Aucune des étapes décrites dans ce didacticiel ne doit être incompatible avec les versions antérieures de Django. J'ai utilisé ces techniques depuis Django 1.8. Cependant, certaines modifications sont nécessaires si vous utilisez Python 2. Pour garder les exemples simples, j'ai supposé Python 3.7 à travers la base de code.

Création du projet Django à partir de zéro

Le projet d'exemple et l'application de reçus ont été créés à l'aide de Django administrateur commande et quelques petites modifications. Pour commencer, exécutez le code suivant à l'intérieur d'un environnement virtuel propre:

$ python -m pip installe Django
$ django-admin startproject sample_project
$ CD sample_project
$ ./manage.py reçus de startapp

Cela crée le sample_project structure du répertoire du projet et un Reçus sous-répertoire de l'application avec des fichiers de modèle que vous utiliserez pour créer votre application Django installable.

Ensuite, le sample_project / settings.py le fichier nécessite quelques modifications:

  • Ajouter «127.0.0.1» à la ALLOWED_HOSTS pour pouvoir tester localement.
  • Ajouter 'Reçus' à la INSTALLED_APPS liste.

Vous devrez également enregistrer le Reçus URL de l'application dans le sample_project / urls.py fichier. Pour ce faire, ajoutez chemin ('receipts /', include ('receipts.urls')) à la url_patterns liste.

Explorer l'exemple d'application Receipts

L'application se compose de deux classes de modèles ORM: Article et Le reçu. le Article La classe contient des déclarations de champ de base de données pour une description et un coût. Le coût est contenu dans un DecimalField. L'utilisation de nombres à virgule flottante pour représenter l'argent est dangereuse – vous devez toujours utiliser des nombres à virgule fixe lorsque vous traitez avec des devises.

le Le reçu la classe est un point de collecte pour Article objets. Ceci est réalisé avec un Clé étrangère sur Article qui pointe vers Le reçu. Le reçu comprend également total() pour obtenir le coût total de Article objets contenus dans le Le reçu:

# receipts / models.py
de décimal importation Décimal
de django.db importation des modèles

classe Le reçu(des modèles.Modèle):
    créé = des modèles.DateTimeField(auto_now_add=Vrai)

    def __str__(soi):
        revenir F"Reçu (id =soi.id) "

    def total(soi) -> Décimal:
        revenir somme(article.Coût pour article dans soi.item_set.tout())

classe Article(des modèles.Modèle):
    créé = des modèles.DateTimeField(auto_now_add=Vrai)

    la description = des modèles.Champ de texte()
    Coût = des modèles.DecimalField(max_digits=7, décimal_places=2)
    le reçu = des modèles.Clé étrangère(Le reçu, on_delete=des modèles.CASCADE)

    def __str__(soi):
        revenir F"Article (id =soi.id, description =soi.la description" 
            F"cost =soi.Coût) "

Les objets de modèle vous fournissent du contenu pour la base de données. Une courte vue Django renvoie un dictionnaire JSON avec tous les Le reçu objets et leurs Article objets dans la base de données:

# receipts / views.py
de django.http importation JsonResponse
de receipts.models importation Le reçu

def reçu_json(demande):
    résultats = 
        "Reçus":[],
    

    pour le reçu dans Le reçu.objets.tout():
        ligne = [[[[str(le reçu), []]
        pour article dans le reçu.item_set.tout():
            ligne[[[[1].ajouter(str(article))

        résultats[[[["Reçus"].ajouter(ligne)

    revenir JsonResponse(résultats)

le reçu_json () voir itère sur tous les Le reçu objets, créant une paire de Le reçu objets et une liste des Article objets contenus à l'intérieur. Tout cela est mis dans un dictionnaire et renvoyé par le biais de Django JsonResponse ().

Pour rendre les modèles disponibles dans l'interface d'administration de Django, vous utilisez un admin.py fichier pour enregistrer les modèles:

# receipts / admin.py
de django.contrib importation administrateur

de receipts.models importation Le reçu, Article

@admin.S'inscrire(Le reçu)
classe ReceiptAdmin(administrateur.ModelAdmin):
    passer

@admin.S'inscrire(Article)
classe ItemAdmin(administrateur.ModelAdmin):
    passer

Ce code crée un Django ModelAdmin pour chacun des Le reçu et Article les classe et les enregistre auprès de l'administrateur Django.

Enfin, un urls.py fichier enregistre une seule vue dans l'application par rapport à une URL:

# receipts / urls.py
de django.urls importation chemin

de Reçus importation vues

urlpatterns = [[[[
    chemin("ticket_json /", vues.reçu_json),
]

Vous pouvez maintenant inclure receipts / urls.py dans votre projet url.py pour rendre la vue des reçus disponible sur votre site Web.

Avec tout en place, vous pouvez courir ./manage.py makemigrations reçus, utilisez l'administrateur Django pour ajouter des données, puis visitez / receipts / ticket_json / pour voir les résultats:

$ curl -sS http://127.0.0.1:8000/receipts/receipt_json/ | python3.8 -m json.tool

                "Reçus":[[[[
                                [[[[
                                                "Reçu (id = 1)",
                                                [[[[
                                                                "Article (id = 1, description = vin, coût = 15,25)",
                                                                "Article (id = 2, description = pâtes, coût = 22,30)"
                                                ]
                                ],
                                [[[[
                                                "Reçu (id = 2)",
                                                [[[[
                                                                "Article (id = 3, description = bière, coût = 8,50)",
                                                                "Article (id = 4, description = pizza, coût = 12.80)"
                                                ]
                                ]
                ]

Dans le bloc ci-dessus, vous utilisez boucle visiter le reçu_json vue, résultant en une réponse JSON contenant le Le reçu objets et leurs correspondants Article objets.

Test de l'application dans le projet

Django augmente le Python Test de l'unité package avec ses propres capacités de test, vous permettant de précharger les appareils dans la base de données et d'exécuter vos tests. L'application reçus définit un tests.py fichier et un appareil pour tester avec. Ce test n'est en aucun cas complet, mais c'est une preuve de concept suffisamment bonne:

# receipts / tests.py
de décimal importation Décimal
de django.test importation Cas de test
de receipts.models importation Le reçu

classe ReceiptTest(Cas de test):
    agencements = [[[["receipts.json", ]

    def test_receipt(soi):
        le reçu = Le reçu.objets.avoir(id=1)
        total = le reçu.total()

        attendu = Décimal("37,55")
        soi.assertEqual(attendu, total)

Le luminaire crée deux Le reçu objets et quatre correspondants Article objets. Cliquez sur la section pliable ci-dessous pour voir de plus près le code du luminaire.

Un banc d'essai Django est un sérialisation des objets dans la base de données. Le code JSON suivant crée Le reçu et Article objets à tester:

[[[[

    "modèle": "receipts.receipt",
    "pk": 1,
    "des champs": 
        "créé": "2020-03-24T18: 16: 39.102Z"
    
,

    "modèle": "receipts.receipt",
    "pk": 2,
    "des champs": 
        "créé": "2020-03-24T18: 16: 41.005Z"
    
,

    "modèle": "receipts.item",
    "pk": 1,
    "des champs": 
        "créé": "2020-03-24T18: 16: 59.357Z",
        "la description": "du vin",
        "Coût": "15,25",
        "le reçu": 1
    
,

    "modèle": "receipts.item",
    "pk": 2,
    "des champs": 
        "créé": "2020-03-24T18: 17: 25.548Z",
        "la description": "Pâtes",
        "Coût": "22.30",
        "le reçu": 1
    
,

    "modèle": "receipts.item",
    "pk": 3,
    "des champs": 
        "créé": "2020-03-24T18: 19: 37.359Z",
        "la description": "Bière",
        "Coût": "8,50",
        "le reçu": 2
    
,

    "modèle": "receipts.item",
    "pk": 4,
    "des champs": 
        "créé": "2020-03-24T18: 19: 51.475Z",
        "la description": "Pizza",
        "Coût": "12.80",
        "le reçu": 2
    

]

Le luminaire ci-dessus est référencé dans le ReceiptTestCase et est chargé automatiquement par le faisceau de test Django.

Vous pouvez tester l'application de reçus avec Django manage.py commander:

$ ./manage.py tester
Création d'une base de données de test pour l'alias 'par défaut' ...
La vérification du système n'a identifié aucun problème (0 désactivé).
.
-------------------------------------------------- --------------------
Test Ran 1 en 0,013 s

D'accord
Détruire la base de données de test pour l'alias 'par défaut' ...

Fonctionnement test manage.py exécute le test unique défini dans receipts / tests.py et affiche les résultats.

Créer votre application Django installable

Votre objectif est de partager l'application de reçus sans projet et de la rendre réutilisable par d'autres. Vous pouvez zipper le Reçus/ répertoire et le distribuer, mais c'est quelque peu limitant. Au lieu de cela, vous souhaitez séparer l'application en un package afin qu'elle soit installable.

Le plus grand défi dans la création d'une application Django installable est que Django attend un projet. Une application sans projet n'est qu'un répertoire contenant du code. Sans projet, Django ne sait rien faire avec votre code, y compris exécuter des tests.

Déplacement de votre application Django hors du projet

C'est une bonne idée de conserver un exemple de projet afin de pouvoir exécuter le serveur de développement Django et jouer avec une version en direct de votre application. Vous n'incluerez pas cet exemple de projet dans le package de l'application, mais il peut toujours vivre dans votre référentiel. En suivant cette idée, vous pouvez commencer à empaqueter votre application Django installable en la déplaçant dans un répertoire:

La structure du répertoire ressemble maintenant à ceci:

django-receipts /
│
├── reçus /
│ ├── luminaires /
│ │ └── receipts.json
│ │
│ ├── migrations /
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ │
│ ├── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ ├── views.py
│ ├── admin.py
│ └── apps.py
│
├── sample_project /
│ ├── sample_project /
│ │ ├── __init__.py
│ │ ├── asgi.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ │
│ ├── db.sqlite3
│ ├── manage.py
│ ├── resetdb.sh
│ └── runserver.sh
│
├── LICENCE
└── README.rst

Pour emballer votre application, vous devez la retirer du projet. Le déplacer est la première étape. Je conserve généralement le projet d'origine pour le tester, mais je ne l'inclus pas dans le package résultant.

Amorcer Django en dehors d'un projet

Maintenant que votre application est en dehors d'un projet Django, vous devez indiquer à Django comment le trouver. Si vous souhaitez tester votre application, exécutez un shell Django qui peut trouver votre application ou exécuter vos migrations. Vous devrez configurer Django et le rendre disponible.

Django's settings.configure () et django.setup () sont essentiels pour interagir avec votre application en dehors d'un projet. Plus d'informations sur ces appels sont disponibles dans la documentation Django.

Vous aurez probablement besoin de cette configuration de Django à plusieurs endroits, il est donc logique de la définir dans une fonction. Créez un fichier appelé boot_django.py contenant le code suivant:

    1 # boot_django.py
    2 #
    3 # Ce fichier configure et configure Django. Il est utilisé par des scripts qui doivent
    4 # s'exécute comme s'il s'exécutait sur un serveur Django.
    5 importation os
    6 importation Django
    7 de django.conf importation réglages
    8 
    9 BASE_DIR = os.chemin.abspath(os.chemin.joindre(os.chemin.dirname(__fichier__), "Reçus"))
dix 
11 def boot_django():
12     réglages.configurer(
13         BASE_DIR=BASE_DIR,
14         DÉBOGUER=Vrai,
15         BASES DE DONNÉES=
16             "défaut": 
17                 "MOTEUR":"django.db.backends.sqlite3",
18                 "NOM": os.chemin.joindre(BASE_DIR, "db.sqlite3"),
19             
20         ,
21         INSTALLED_APPS=(
22             "Reçus",
23         ),
24         FUSEAU HORAIRE="UTC",
25         USE_TZ=Vrai,
26     )
27     Django.installer()

Lignes 12 et 27 configurer l'environnement Django. le settings.configure () l'appel prend une liste d'arguments équivalents aux variables définies dans un settings.py fichier. Tout ce dont vous auriez besoin dans votre settings.py pour faire fonctionner votre application settings.configure ().

Le code ci-dessus est une configuration assez épurée. L'application de reçus ne fait rien avec les sessions ou les modèles, donc INSTALLED_APPS a seulement besoin "Reçus"et vous pouvez ignorer toutes les définitions de middleware. le USE_TZ = True est nécessaire car la Le reçu le modèle contient un créé horodatage. Sinon, vous rencontreriez des problèmes lors du chargement du dispositif de test.

Exécution de commandes de gestion avec votre application Django installable

Maintenant que vous avez boot_django.py, vous pouvez exécuter n'importe quelle commande de gestion Django avec un script très court:

#! / usr / bin / env python
# makemigrations.py

de django.core.management importation call_command
de boot_django importation boot_django

boot_django()
call_command("makemigrations", "Reçus")

Django vous permet d'appeler par programmation des commandes de gestion via call_command (). Vous pouvez maintenant exécuter n'importe quelle commande de gestion en important et en appelant boot_django () suivi par call_command ().

Votre application est désormais en dehors du projet, ce qui vous permet de lui faire toutes sortes de choses. Je définis souvent quatre scripts utilitaires:

  1. load_tests.py pour tester votre application
  2. makemigrations.py créer des fichiers de migration
  3. migrate.py effectuer des migrations de table
  4. djangoshell.py pour générer un shell Django qui connaît votre application

Test de votre application Django installable

le load_test.py fichier pourrait être aussi simple que le makemigrations.py script, mais il ne pourrait alors exécuter tous les tests à la fois. Avec quelques lignes supplémentaires, vous pouvez passer des arguments de ligne de commande au lanceur de test, ce qui vous permet d'exécuter des tests sélectifs:

    1 #! / usr / bin / env python
    2 # load_tests.py
    3 importation sys
    4 de Test de l'unité importation Suite de tests
    5 de boot_django importation boot_django
    6 
    7 boot_django()
    8 
    9 default_labels = [[[["receipts.tests", ]
dix 
11 def get_suite(Étiquettes=default_labels):
12     de django.test.runner importation DiscoverRunner
13     coureur = DiscoverRunner(verbosité=1)
14     les échecs = coureur.run_tests(Étiquettes)
15     si les échecs:
16         sys.sortie(les échecs)
17 
18     # Si cela est appelé depuis setuptools, retournez une suite de tests
19     revenir Suite de tests()
20 
21 si __Nom__ == "__principale__":
22     Étiquettes = default_labels
23     si len(sys.argv[[[[1:]) > 0:
24         Étiquettes = sys.argv[[[[1:]
25 
26     get_suite(Étiquettes)

Django's DiscoverRunner est une classe de découverte de test compatible avec Python Test de l'unité. Il est responsable de la configuration de l'environnement de test, de la création de la suite de tests, de la configuration des bases de données, de l'exécution des tests, puis de tout démonter. À partir de ligne 11, get_suite () prend une liste d'étiquettes de test et appelle directement le DiscoverRunner sur eux.

Ce script est similaire à ce que la commande de gestion Django tester Est-ce que. le __principale__ le bloc transmet tous les arguments de ligne de commande à get_suite (), et s'il n'y en a pas, il passe dans la suite de tests de l'application, receipts.tests. Vous pouvez maintenant appeler load_tests.py avec un argument d'étiquette de test et exécutez un seul test.

Ligne 19 est un cas spécial pour aider lors des tests avec tox. Vous en apprendrez plus sur tox dans une section ultérieure. Vous pouvez également consulter un substitut potentiel pour DiscoverRunner dans la section repliable ci-dessous.

L'une des applications Django installables que j'ai écrites est django-awl. C’est une collection lâche d’utilitaires que j’ai accumulée au cours de mes années en écrivant des projets Django. Inclus dans le package est une alternative à DiscoverRunner appelé WRunner.

L'avantage clé de l'utilisation WRunner c'est qu'il supporte correspondance générique d'étiquettes de test. Passer une étiquette commençant par un signe égal (=) correspondra à toute suite de tests ou nom de méthode qui contient cette étiquette en tant que sous-chaîne. Par exemple, l'étiquette = rec correspondrait et exécuterait le test ReceiptTest.test_receipt () dans reçu / tests.py.

Définition de votre package installable avec setup.cfg

Pour mettre votre application Django installable sur PyPI, vous devez d'abord la mettre dans un package. PyPI attend un Oeuf, roueou la distribution source. Ceux-ci sont construits en utilisant setuptools. Pour ce faire, vous devez créer un setup.cfg fichier et un setup.py fichier au même niveau de répertoire que votre Reçus annuaire.

Avant de creuser, cependant, vous devez vous assurer que vous avez une documentation. Vous pouvez inclure une description de projet dans setup.cfg, qui s'affiche automatiquement sur la page du projet PyPI. Assurez-vous d'écrire un README.rst ou quelque chose de similaire avec des informations sur votre colis.

PyPI prend en charge le format reStructuredText par défaut, mais il peut également gérer Markdown avec des paramètres supplémentaires:

    1 # setup.cfg
    2 [metadata]
    3 Nom = realpython-django-receipts
    4 version = 1.0.3
    5 la description = Exemple d'application Django installable
    6 longue description = fichier: README.rst
    7 url = https://github.com/realpython/django-receipts
    8 Licence = MIT
    9 classificateurs =
dix                 Statut de développement :: 4 - Beta
11                 Environnement :: Environnement Web
12                 Public cible :: Développeurs
13                 Licence :: Approuvé OSI :: Licence MIT
14                 Système d'exploitation :: Indépendant du système d'exploitation
15                 Langage de programmation :: Python :: 3 :: Uniquement
16                 Langage de programmation :: Python :: 3.7
17                 Langage de programmation :: Python :: Implémentation :: CPython
18                 Sujet :: Développement de logiciels :: Bibliothèques :: Cadres d'application
19                 Sujet :: Développement de logiciels :: Bibliothèques :: Modules Python
20 
21 [options]
22 include_package_data = vrai
23 python_requires = > = 3,6
24 setup_requires =
25                 setuptools> = 38.3.0
26 install_requires =
27                 Django> = 2,2

Cette setup.cfg Le fichier décrit le package que vous allez créer. Ligne 6 utilise le fichier: directive à lire dans votre README.rst fichier. Cela vous évite d'avoir à écrire une longue description à deux endroits.

le install_requires entrée le ligne 26 indique à tous les installateurs, tels que installer pip, sur les dépendances de votre application. Vous voudrez toujours lier votre application Django installable à sa version minimale prise en charge de Django.

Si votre code a des dépendances qui ne sont nécessaires que pour exécuter les tests, vous pouvez ajouter un tests_require = entrée. Par exemple, avant moquer est devenu une partie de la bibliothèque Python standard, il était courant de voir tests_require = mock> = 2.0.0 dans setup.cfg.

Il est considéré comme la meilleure pratique d'inclure un pyproject.toml déposer avec votre colis. L’excellent article de Brett Cannon sur le sujet peut vous expliquer les détails. UNE pyproject.toml est également inclus avec l'exemple de code.

Vous êtes presque prêt à créer le package pour votre application Django installable. Le moyen le plus simple de le tester est avec votre exemple de projet – une autre bonne raison de conserver un exemple de projet. le installer pip La commande prend en charge les packages définis localement. Cela peut être utilisé pour vous assurer que votre application fonctionne toujours avec un projet. Cependant, une mise en garde est que setup.cfg ne fonctionnera pas seul dans ce cas. Vous devrez également créer une version shim de setup.py:

#! / usr / bin / env python

si __Nom__ == "__principale__":
    importation setuptools
    setuptools.installer()

Ce script utilisera automatiquement votre setup.cfg fichier. Vous pouvez maintenant installer un local modifiable version du package pour le tester de l'intérieur sample_project. Pour être sûr, il est préférable de commencer avec un tout nouvel environnement virtuel. Ajoutez ce qui suit requirements.txt fichier à l'intérieur du sample_project annuaire:

# requirements.txt
-e ../../django-receipts

le -e raconte pépin qu'il s'agit d'une installation locale modifiable. Vous êtes maintenant prêt à installer:

$ pip install -r requirements.txt
Obtention de django-receipts (à partir de -r requirements.txt (ligne 1))
Collecte de Django> = 3.0
        Utilisation de Django-3.0.4-py3-none-any.whl en cache (7,5 Mo)
Collecte asgiref ~ = 3,2
        Utilisation de asgiref-3.2.7-py2.py3-none-any.whl en cache (19 ko)
Collectionner pytz
        Utilisation de pytz-2019.3-py2.py3-none-any.whl en cache (509 Ko)
Collecte sqlparse> = 0.2.2
        Utilisation de sqlparse-0.3.1-py2.py3-none-any.whl en cache (40 Ko)
Installation des packages collectés: asgiref, pytz, sqlparse, Django, realpython-django-receipts
        Exécution de setup.py develop pour realpython-django-receipts
Django-3.0.4 asgiref-3.2.7 pytz-2019.3 realpython-django-receipts sqlparse-0.3.1 installé avec succès

le install_requires liste dans setup.cfg raconte installer pip qu'il a besoin de Django. Django a besoin asgiref, pytz, et sqlparse. Toutes les dépendances sont prises en charge et vous devriez maintenant pouvoir exécuter votre sample_project Serveur de développement Django. Félicitations, votre application est désormais packagée et référencée à partir de l'exemple de projet!

Test de plusieurs versions avec tox

Django et Python avancent tous les deux constamment. Si vous allez partager votre application Django installable avec le monde, vous devrez probablement tester dans plusieurs environnements. le tox L'outil a besoin d'un peu d'aide pour pouvoir tester votre application Django. Allez-y et effectuez le changement suivant à l'intérieur de setup.cfg:

    1 # setup.cfg
    2 [metadata]
    3 Nom = realpython-django-receipts
    4 version = 1.0.3
    5 la description = Exemple d'application Django installable
    6 longue description = fichier: README.rst
    7 url = https://github.com/realpython/django-receipts
    8 Licence = MIT
    9 classificateurs =
dix                 Statut de développement :: 4 - Beta
11                 Environnement :: Environnement Web
12                 Public cible :: Développeurs
13                 Licence :: Approuvé OSI :: Licence MIT
14                 Système d'exploitation :: Indépendant du système d'exploitation
15                 Langage de programmation :: Python :: 3 :: Uniquement
16                 Langage de programmation :: Python :: 3.7
17                 Langage de programmation :: Python :: Implémentation :: CPython
18                 Sujet :: Développement de logiciels :: Bibliothèques :: Cadres d'application
19                 Sujet :: Développement de logiciels :: Bibliothèques :: Modules Python
20 
21 [options]
22 include_package_data = vrai
23 python_requires = > = 3,6
24 setup_requires =
25                 setuptools> = 38.3.0
26 install_requires =
27                 Django> = 2,2
28 suite de tests = load_tests.get_suite

Ligne 28 indique au gestionnaire de packages d'utiliser le load_tests.py script pour obtenir sa suite de tests. le tox l'utilitaire l'utilise pour exécuter ses tests. Rappel get_suite () dans load_tests.py:

    1 # Défini dans load_tests.py
    2 def get_suite(Étiquettes=default_labels):
    3     de django.test.runner importation DiscoverRunner
    4     coureur = DiscoverRunner(verbosité=1)
    5     les échecs = coureur.run_tests(Étiquettes)
    6     si les échecs:
    7         sys.sortie(les échecs)
    8 
    9     # Si cela est appelé depuis setuptools, alors retournez une suite de tests
dix     revenir Suite de tests()

Ce qui se passe ici est certes un peu bizarre. Normalement, le suite de tests champ dans setup.cfg pointe vers une méthode qui renvoie une suite de tests. Quand tox appels setup.py, il lit le suite de tests paramètre et exécute load_tests.get_suite ().

Si cet appel n'a pas renvoyé Suite de tests objet, puis tox se plaindrait. La partie bizarre est que vous ne voulez pas vraiment tox pour obtenir une suite de tests, car tox n'est pas au courant de l'environnement de test Django. Au lieu, get_suite () crée un DiscoverRunner et retourne un vide Suite de tests objet sur ligne 10.

Vous ne pouvez pas simplement avoir DiscoverRunner retourner une suite de tests parce que vous devez appeler DiscoverRunner.run_tests () pour que la configuration et le démontage de l'environnement de test Django s'exécutent correctement. Passer simplement les bons tests à tox ne fonctionnerait pas car la base de données ne serait pas créée. get_suite () exécute tous les tests, mais comme effet secondaire de l'appel de fonction plutôt que comme le cas normal du renvoi d'une suite de tests pour tox éxécuter.

le tox L'outil vous permet de tester plusieurs combinaisons. UNE tox.ini Le fichier détermine les combinaisons d'environnements à tester. Voici un exemple:

[tox]
envlist = py 36,37 -django220, py 36,37 -django300

[testenv]
deps =
                django220: Django> = 2.2, <3
                django300: Django> = 3
commandes=
                test setup.py de python

Ce fichier indique que les tests doivent être exécutés pour Python 3.6 et 3.7 combinés avec Django 2.2 et 3.0. C'est un total de quatre environnements de test. le commandes = la section est où vous dites tox pour passer le test setup.py. Voici comment vous invoquez le test_suite = load_tests.get_suite accrocher setup.cfg.

Publication sur PyPI

Enfin, il est temps de partager votre application Django installable sur PyPI. Il existe plusieurs outils pour télécharger un package, mais vous vous concentrerez sur Twine dans ce didacticiel. Le code suivant crée les packages et appelle Twine:

$ python -m pip install -U ensemble de ficelles de roue U
$ python setup.py sdist
$ python setup.py bdist_wheel
$ téléchargement de ficelle dist / *

Les deux premières commandes génèrent les distributions source et binaire de votre package. L'appel à ficelle télécharge sur PyPI. Si tu as un .pypirc fichier dans votre répertoire personnel, vous pouvez prédéfinir votre nom d’utilisateur afin que la seule chose que vous soyez invité soit votre mot de passe:

[disutils]
serveurs d'index =
                pypi

[pypi]
Nom d'utilisateur: 

J'utilise souvent un petit script shell pour grep le numéro de version du code. Ensuite j'appelle git tag pour marquer le référentiel avec le numéro de version, supprimez l'ancien construire/ et dist / et appelez les trois commandes ci-dessus.

Pour plus de détails sur l'utilisation de Twine, consultez Comment publier un package Python Open Source sur PyPI. Deux alternatives populaires à Twine sont la poésie et Flit. La gestion des packages en Python évolue rapidement. PEP 517 et PEP 518 redéfinissent la façon de décrire les packages et les dépendances Python.

Conclusion

Les applications Django reposent sur la structure du projet Django, donc les empaqueter séparément nécessite des étapes supplémentaires. Vous avez vu comment créer une application Django installable en l'extrayant d'un projet, en l'empaquetant et en la partageant sur PyPI. Assurez-vous de télécharger l'exemple de code sur le lien ci-dessous:

Dans ce didacticiel, vous avez appris à:

  • Utilisez le Framework Django en dehors d'un projet
  • Appelez Django commandes de gestion sur une application indépendante d'un projet
  • Écrivez un script qui invoque Tests Django, en utilisant éventuellement une seule étiquette de test
  • Construire un setup.py fichier définir votre forfait
  • Modifier le setup.py script pour accueillir tox
  • Utilisation Ficelle pour télécharger votre application Django installable

Vous êtes prêt à partager votre prochaine application avec le monde. Bon codage!

Lectures complémentaires

Django, le packaging et les tests sont tous des sujets très profonds. Il y a beaucoup d'informations là-bas. Pour approfondir, consultez les ressources suivantes:

PyPI dispose de nombreuses applications Django installables qui valent la peine d'être essayées. Voici quelques-uns des plus populaires: