# Django 6.0.7 documentation

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

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

如果你最近没有完成教程 1-8，我们鼓励你回顾这些内容，以便你的示例项目与下面描述的项目相匹配。

## 可重用性很重要

设计，构建，测试以及维护一个 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.bar` 或 `from foo import bar` 的形式导入。一个目录（例如 `polls`）要成为一个包，它必须包含一个特定的文件 `__init__.py`，即便这个文件是空的。

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

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

## 你的项目和可复用应用

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

    djangotutorial/
        manage.py
        mysite/
            __init__.py
            settings.py
            urls.py
            asgi.py
            wsgi.py
        polls/
            __init__.py
            admin.py
            apps.py
            migrations/
                __init__.py
                0001_initial.py
            models.py
            static/
                polls/
                    images/
                        background.png
                    style.css
            templates/
                polls/
                    detail.html
                    index.html
                    results.html
            tests.py
            urls.py
            views.py
        templates/
            admin/
                base_site.html

你在 教程 7 中创建了 `djangotutorial/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 文档中相同的标签名，比如 `auth`，`admin`，`messages`。

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

3. 编辑 `django_polls/apps.py`，使 `name` 指向新的模块名称，添加 `label` 为应用程序提供一个简短的名称，并设置 `default_auto_field` 以确保你的迁移不受你的可重用应用程序的用户对 `DEFAULT_AUTO_FIELD` 所作改动的影响。

   `django-polls/django_polls/apps.py`

       from django.apps import AppConfig

       class PollsConfig(AppConfig):
           default_auto_field = "django.db.models.BigAutoField"
           name = "django_polls"
           label = "polls"

4. 创建一个名为 `django-polls/README.rst` 的文件，包含以下内容：

   `django-polls/README.rst`

       ============
       django-polls
       ============

       django-polls is a Django app to conduct web-based polls. For each
       question, visitors can choose between a fixed number of answers.

       Detailed documentation is in the "docs" directory.

       Quick start
       -----------

       1. Add "polls" to your INSTALLED_APPS setting like this::

           INSTALLED_APPS = [
               ...,
               "django_polls",
           ]

       2. Include the polls URLconf in your project urls.py like this::

           path("polls/", include("django_polls.urls")),

       3. Run ``python manage.py migrate`` to create the models.

       4. Start the development server and visit the admin to create a poll.

       5. Visit the ``/polls/`` URL to participate in the poll.

5. 创建一个 `django-polls/LICENSE` 文件。选择一个非本教程使用的授权协议，但是要足以说明发布代码没有授权证书是 不可能的 。Django 和很多兼容 Django 的应用是以 BSD 授权协议发布的；不过，你可以自己选择一个授权协议。只要确定你选择的协议能够限制未来会使用你的代码的人。

6. 接下来我们将创建 `pyproject.toml` 文件，该文件详细说明了如何构建和安装应用程序。对这个文件的完整解释超出了本教程的范围，但 Python 打包用户指南 提供了很好的解释。创建 `django-polls/pyproject.toml` 文件，内容如下：

   `django-polls/pyproject.toml`

       [build-system]
       requires = ["setuptools>83"]
       build-backend = "setuptools.build_meta"

       [project]
       name = "django-polls"
       version = "0.1"
       dependencies = [
           "django>=X.Y",  # Replace "X.Y" as appropriate
       ]
       description = "A Django app to conduct web-based polls."
       readme = "README.rst"
       license = "BSD-3-Clause"
       requires-python = ">= 3.12"
       authors = [
           {name = "Your Name", email = "yourname@example.com"},
       ]
       classifiers = [
           "Environment :: Web Environment",
           "Framework :: Django",
           "Framework :: Django :: X.Y",  # Replace "X.Y" as appropriate
           "Intended Audience :: Developers",
           "Operating System :: OS Independent",
           "Programming Language :: Python",
           "Programming Language :: Python :: 3",
           "Programming Language :: Python :: 3 :: Only",
           "Programming Language :: Python :: 3.12",
           "Programming Language :: Python :: 3.13",
           "Programming Language :: Python :: 3.14",
           "Topic :: Internet :: WWW/HTTP",
           "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
       ]

       [project.urls]
       Homepage = "https://www.example.com/"

7. 默认情况下，许多常见文件和 Python 模块及包已经包含在包中。要包含额外的文件，我们需要创建一个 `MANIFEST.in` 文件。为了包含模板和静态文件，创建一个文件 `django-polls/MANIFEST.in`，内容如下：

   `django-polls/MANIFEST.in`

       recursive-include django_polls/static *
       recursive-include django_polls/templates *

8. 虽然不是必须的，但建议为你的应用程序包含详细的文档。创建一个空目录 `django-polls/docs` 以便将来存放文档。

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

   许多 Python 项目，包括 Django 和 Python 自身，都使用 Sphinx 来构建文档。如果你选择使用 Sphinx，可以通过配置 Intersphinx 并在项目的 `intersphinx_mapping` 值中包含 Django 的映射值，来链接回 Django 文档：

       intersphinx_mapping = {
           # ...
           "django": (
               "https://docs.djangoproject.com/en/stable/",
               None,
           ),
       }

   配置完成后，你就可以像在 Django 文档中那样进行跨链接引用特定条目，例如 "`:attr:`django.test.TransactionTestCase.databases``"。

9. 请确认已安装 build 包（使用 `python -m pip install build` 命令），然后在 `django-polls` 目录内运行 `python -m build` 尝试构建你的包。这将会创建一个名为 `dist` 的目录，并将你的新包构建成源码格式和二进制格式：`django_polls-0.1.tar.gz` 和 `django_polls-0.1-py3-none-any.whl`。

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

## 使用你自己的包名

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

作为用户库安装

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

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

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

       python -m pip install --user django-polls/dist/django_polls-0.1.tar.gz

2. 更新 `mysite/settings.py` 以指向新的模块名称：

       INSTALLED_APPS = [
           "django_polls.apps.PollsConfig",
           ...,
       ]

3. 更新 `mysite/urls.py` 以指向新的模块名称：

       urlpatterns = [
           path("polls/", include("django_polls.urls")),
           ...,
       ]

4. 运行开发服务器以确认项目继续工作。

## 发布你的应用

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

- 通过邮件将你的包发送给朋友。

- 将这个包上传至你的网站。

- 将包发布到公共存储库上，例如 the Python Package Index (PyPI)。有一个很好的教程 来教你怎么做。

## 通过虚拟环境安装 Python 包

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

- 修改用户库会影响你系统上的其他 Python 软件。

- 你将不能运行此包的多个版本（或者其它用有相同包名的包）。

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