进阶指南:如何编写可重用程序

这个进阶教程从 教程第 8 部分 结束的地方继续讲起。我们将会把我们的网络投票应用放进一个独立的 Python 包中,以便你在新的项目中重用它或将它与他人分享。

如果你尚未完成教程 1-7,我们推荐你先浏览一遍教程,这样你的样例工程会和下面的一致。

可重用性很重要

设计,构建,测试以及维护一个 web 应用要做很多的工作。很多 Python 以及 Django 项目都有一些常见问题。如果我们能保存并利用这些重复的工作岂不是更好?

可重用性是 Python 的根本。The Python Package Index (PyPI) 有许大量的包,都可被用在你自己的 Python 项目中。同样可以在 Django Packages 中查找已发布的可重用应用,也可将其引入到你的项目中。Django 本身也是一个 Python 包,也就是说你可以将已有的 Python 包或 Django 应用并入你的项目。你只需要编写属于你的那部分即可。

假设你现在创建了一个新的项目,并且需要一个类似我们之前做的投票应用。你该如何复用这个应用呢?庆幸的是,其实你已经知道了一些。在 教程 1,我们使用过 include 从项目级别的 URLconf 分割出 polls。在本教程中,我们将进一步使这个应用易用于新的项目中,并发布给其他人安装使用。

包?应用?

一个 package 提供了一组关联的 Python 代码的简单复用方式。一个包(“模块”)包含了一个或多个 Python 代码文件。

一个包通过 import foo.barfrom foo import bar 的形式导入。一个目录(例如 polls)要成为一个包,它必须包含一个特定的文件 __init__.py,即便这个文件是空的。

Django 应用 仅仅是专用于 Django 项目的 Python 包。应用会按照 Django 规则,创建好 models, tests, urls, 以及 views 等子模块。

稍后,我们将解释术语 打包 ——为了方便其它人安装 Python 包的处理流程。我知道,这可能会使你感到一点点迷惑。

你的项目和可复用应用

通过前面的教程,我们的工程应该看起来像这样:

  1. mysite/
  2. manage.py
  3. mysite/
  4. __init__.py
  5. settings.py
  6. urls.py
  7. asgi.py
  8. wsgi.py
  9. polls/
  10. __init__.py
  11. admin.py
  12. apps.py
  13. migrations/
  14. __init__.py
  15. 0001_initial.py
  16. models.py
  17. static/
  18. polls/
  19. images/
  20. background.png
  21. style.css
  22. templates/
  23. polls/
  24. detail.html
  25. index.html
  26. results.html
  27. tests.py
  28. urls.py
  29. views.py
  30. templates/
  31. admin/
  32. base_site.html

你在 教程 7 中创建了 mysite/templates,在 教程 3 中创建了 polls/templates。现在也许更清楚为什么我们选择为项目和应用程序设置单独的模板目录:所有属于 polls 应用程序的部分都在 polls 中。这使得应用程序自成一体,更容易放到一个新项目中。

目录 polls 现在可以被拷贝至一个新的 Django 工程,且立刻被复用。不过现在还不是发布它的时候。为了这样做,我们需要打包这个应用,便于其他人安装它。

安装必须环境

Python 包装的当前状态有些混乱,有各种各样的工具。对于本教程,我们将使用 setuptools 来构建我们的包。它是推荐的打包工具(与 distribute 分支合并)。我们还将使用 pip 来安装和卸载它。你现在应该安装这两个包。如果你需要帮助,可以参考 如何使用 pip 安装 Django。你可以以相同的方式安装 setuptools

打包你的应用

Python 的 打包 将以一种特殊的格式组织你的应用,意在方便安装和使用这个应用。Django 本身就被打包成类似的形式。对于一个小应用,例如 polls,这不会太难。

  1. 首先,在 Django 项目之外创建一个父目录来存放包。将该目录命名为 django-polls

    为你的应用选择一个名字

    选择软件包名称时,请在 PyPI 上检查以避免与现有软件包命名冲突。我们建议为软件包名称使用 django- 前缀,以标识你的软件包特定于 Django,并为你的模块名称使用相应的 django_ 前缀。例如,django-ratelimit 软件包包含 django_ratelimit 模块。

    应用标签(指用点分隔的包名的最后一部分)在 INSTALLED_APPS必须 是独一无二的。避免使用任何与 Django contrib packages 文档中相同的标签名,比如 authadminmessages

  2. polls 目录移动到 django-polls 目录中,并将其重命名为 django_polls

  3. 编辑 django_polls/apps.py,使 name 指向新的模块名称,并添加 label 以为应用程序提供一个简短的名称:

    django-polls/django_polls/apps.py

    ``` from django.apps import AppConfig

  1. class PollsConfig(AppConfig):
  2. default_auto_field = "django.db.models.BigAutoField"
  3. name = "django_polls"
  4. label = "polls"
  5. ```
  1. 创建一个名为 django-polls/README.rst 的文件,包含以下内容:

    django-polls/README.rst

    1. ============
    2. django-polls
    3. ============
    4. django-polls is a Django app to conduct web-based polls. For each
    5. question, visitors can choose between a fixed number of answers.
    6. Detailed documentation is in the "docs" directory.
    7. Quick start
    8. -----------
    9. 1. Add "polls" to your INSTALLED_APPS setting like this::
    10. INSTALLED_APPS = [
    11. ...,
    12. "django_polls",
    13. ]
    14. 2. Include the polls URLconf in your project urls.py like this::
    15. path("polls/", include("django_polls.urls")),
    16. 3. Run ``python manage.py migrate`` to create the models.
    17. 4. Start the development server and visit the admin to create a poll.
    18. 5. Visit the ``/polls/`` URL to participate in the poll.
  2. 创建一个 django-polls/LICENSE 文件。选择一个非本教程使用的授权协议,但是要足以说明发布代码没有授权证书是 不可能的 。Django 和很多兼容 Django 的应用是以 BSD 授权协议发布的;不过,你可以自己选择一个授权协议。只要确定你选择的协议能够限制未来会使用你的代码的人。

  3. Next we’ll create the pyproject.toml file which details how to build and install the app. A full explanation of this file is beyond the scope of this tutorial, but the Python Packaging User Guide has a good explanation. Create the django-polls/pyproject.toml file with the following contents:

    django-polls/pyproject.toml

    1. [build-system]
    2. requires = ["setuptools>=61.0"]
    3. build-backend = "setuptools.build_meta"
    4. [project]
    5. name = "django-polls"
    6. version = "0.1"
    7. dependencies = [
    8. "django>=X.Y", # Replace "X.Y" as appropriate
    9. ]
    10. description = "A Django app to conduct web-based polls."
    11. readme = "README.rst"
    12. requires-python = ">= 3.10"
    13. authors = [
    14. {name = "Your Name", email = "yourname@example.com"},
    15. ]
    16. classifiers = [
    17. "Environment :: Web Environment",
    18. "Framework :: Django",
    19. "Framework :: Django :: X.Y", # Replace "X.Y" as appropriate
    20. "Intended Audience :: Developers",
    21. "License :: OSI Approved :: BSD License",
    22. "Operating System :: OS Independent",
    23. "Programming Language :: Python",
    24. "Programming Language :: Python :: 3",
    25. "Programming Language :: Python :: 3 :: Only",
    26. "Programming Language :: Python :: 3.10",
    27. "Programming Language :: Python :: 3.11",
    28. "Programming Language :: Python :: 3.12",
    29. "Topic :: Internet :: WWW/HTTP",
    30. "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
    31. ]
    32. [project.urls]
    33. Homepage = "https://www.example.com/"
  4. Many common files and Python modules and packages are included in the package by default. To include additional files, we’ll need to create a MANIFEST.in file. To include the templates and static files, create a file django-polls/MANIFEST.in with the following contents:

    django-polls/MANIFEST.in

    1. recursive-include django_polls/static *
    2. recursive-include django_polls/templates *
  5. It’s optional, but recommended, to include detailed documentation with your app. Create an empty directory django-polls/docs for future documentation.

    注意,现在 docs 目录不会被加入你的应用包,除非你往这个目录加几个文件。许多 Django 应用也提供他们的在线文档通过类似 readthedocs.org 这样的网站。

  6. Check that the build package is installed (python -m pip install build) and try building your package by running python -m build inside django-polls. This creates a directory called dist and builds your new package into source and binary formats, django-polls-0.1.tar.gz and django_polls-0.1-py3-none-any.whl.

更多关于打包的信息,见 Python 的 关于打包和发布项目的教程

使用你自己的包名

由于我们把 polls 目录移出了项目,所以它无法工作了。我们现在要通过安装我们的新 django-polls 应用来修复这个问题。

作为用户库安装

以下步骤将 django-polls 以用户库的形式安装。与安装整个系统的软件包相比,用户安装具有许多优点,例如可在没有管理员访问权的系统上使用,以及防止应用包影响系统服务和其他用户。

请注意,按用户安装仍然会影响以该用户身份运行的系统工具的行为,因此使用虚拟环境是更可靠的解决方案(请参见下文)。

  1. 为了安装这个包,使用 pip (你早已 安装 pip, 对吗?):

    1. python -m pip install --user django-polls/dist/django-polls-0.1.tar.gz
  2. 更新 mysite/settings.py 以指向新的模块名称:

    1. INSTALLED_APPS = [
    2. "django_polls.apps.PollsConfig",
    3. ...,
    4. ]
  3. 更新 mysite/urls.py 以指向新的模块名称:

    1. urlpatterns = [
    2. path("polls/", include("django_polls.urls")),
    3. ...,
    4. ]
  4. 运行开发服务器以确认项目继续工作。

发布你的应用

现在,你已经对 django-polls 完成了打包和测试,准备好向世界分享它!如果这不是一个例子应用,你现在就可以这样做。

通过虚拟环境安装 Python 包

早些时候,我们将 django-polls 安装为用户库。这样做有一些不利之处:

  • 修改用户库会影响你系统上的其他 Python 软件。
  • 你将不能运行此包的多个版本(或者其它用有相同包名的包)。

通常,只有在维护多个 Django 项目时才会出现这些情况。当这样做时,最好的解决方法是使用 venv。使用此工具,你可以维护多个隔离的 Python 环境,每个环境都有其自己的库和包命名空间的副本。