---
title: "进阶指南：如何编写可重用程序"
version: 2.1
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/2.1/intro/reusable-apps/
canonical: https://djangodocs.dev/zh-hans/2.1/intro/reusable-apps/
---
# 进阶指南：如何编写可重用程序

这篇进阶指南从 [Tutorial 7](/zh-hans/2.1/intro/tutorial07/) 结尾的地方继续讲起。我们将会把我们的 Web-poll 放进一个独立的 Python 包中，以便你在新的项目中重用它或将它与他人分享。

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

## 可重用性很重要

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

可重用性是Python的生存方式。 [Python软件包索引（PyPI）](https://pypi.org/) 有很多可以在你自己的Python程序中使用的软件包。查看 [Django Packages](https://djangopackages.org) 以了解您可以整合到项目中的现有可重用应用。Django本身也只是一个Python包。这意味着您可以将现有的Python包或Django应用组合到您自己的Web项目中。您只需编写您项目独一无二的部分。

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

> **包？应用？**
>
> 一个 [package](https://docs.python.org/3/glossary.html#term-package) 提供了一组关联的 Python 代码的简单复用方式。一个包（“模块”）包含了一个或多个 Python 代码文件。
>
> 一个包通过 `import foo.bar` 或 `from foo import bar` 的形式导入。一个目录（例如 `polls`）要成为一个包，它必须包含一个特定的文件 `__init__.py`，即便这个文件是空的。
>
> Django *应用* 仅仅是专用于 Django 项目的 Python 包。应用会按照 Django 约定，创建好 `models`,  `tests`,  `urls`, 以及 `views` 等子模块。
>
> 稍后，我们将解释术语 *打包* ——为了方便其它人安装 Python 包的处理流程。我知道，这可能会使你感到一点点迷惑。

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

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

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

1

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

## 安装必须环境

目前，打包 Python 程序需要工具，有许多工具可以完成此项工作。在此教程中，我们将使用 [setuptools](https://pypi.org/project/setuptools/) 来打包我们的程序。这是推荐的打包工具（与 `发布` 分支合并）。我们仍旧使用 [pip](https://pypi.org/project/pip/) 来安装和卸载这个工具。现在，你需要安装这两个包。如果你需要帮助，你可以参考 [如何通过 pip 安装 Django](/zh-hans/2.1/topics/install/#installing-official-release)，你可以通过相同的方式安装 `setuptools`。

## 打包你的应用

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

1. 首先，在你的 Django 项目目录外创建一个名为 `django-polls` 的文件夹，用于盛放 `polls`。

   > **为你的应用选择一个名字**
   >
   > 当为你的包选一个名字时，避免使用像 PyPI 这样已存在的包名，否则会导致冲突。当你创建你的发布包时，可以在模块名前增加 `django-` 前缀，这是一个很常用也很有用的避免包名冲突的方法。同时也有助于他人在寻找 Django 应用时确认你的 app 是 Django 独有的。
   >
   > 应用标签（指用点分隔的包名的最后一部分）在 [`INSTALLED_APPS`](/zh-hans/2.1/ref/settings/#std-setting-INSTALLED_APPS) 中 *必须* 是独一无二的。避免使用任何与 Django [contrib packages](/zh-hans/2.1/ref/contrib/) 文档中相同的标签名，比如 `auth`，`admin`，`messages`。
2. 将 `polls` 目录移入 `django-polls` 目录。
3. 创建一个名为 `django-polls/README.rst` 的文件，包含以下内容：

   *django-polls/README.rst*

   ```rst
   =====
   Polls
   =====

   Polls is a simple 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 = [
           ...
           'polls',
       ]

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

       path('polls/', include('polls.urls')),

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

   4. Start the development server and visit http://127.0.0.1:8000/admin/
      to create a poll (you'll need the Admin app enabled).

   5. Visit http://127.0.0.1:8000/polls/ to participate in the poll.
   ```
4. 创建一个 `django-polls/LICENSE` 文件。选择一个非本教程使用的授权协议，但是要足以说明发布代码没有授权证书是 *不可能的* 。Django 和很多兼容 Django 的应用是以 BSD 授权协议发布的；不过，你可以自己选择一个授权协议。只要确定你选择的协议能够限制未来会使用你的代码的人。
5. 下一步我们将创建 `setup.py` 用于说明如何构建和安装应用的细节。关于此文件的完整介绍超出了此教程的范围，但是 [setuptools docs](https://setuptools.readthedocs.io/en/latest/) 有详细的介绍。创建文件 `django-polls/setup.py` 包含以下内容：

   *django-polls/setup.py*

   ```python
   import os
   from setuptools import find_packages, setup

   with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
       README = readme.read()

   # allow setup.py to be run from any path
   os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))

   setup(
       name='django-polls',
       version='0.1',
       packages=find_packages(),
       include_package_data=True,
       license='BSD License',  # example license
       description='A simple Django app to conduct Web-based polls.',
       long_description=README,
       url='https://www.example.com/',
       author='Your Name',
       author_email='yourname@example.com',
       classifiers=[
           'Environment :: Web Environment',
           'Framework :: Django',
           'Framework :: Django :: X.Y',  # replace "X.Y" as appropriate
           'Intended Audience :: Developers',
           'License :: OSI Approved :: BSD License',  # example license
           'Operating System :: OS Independent',
           'Programming Language :: Python',
           'Programming Language :: Python :: 3.5',
           'Programming Language :: Python :: 3.6',
           'Topic :: Internet :: WWW/HTTP',
           'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
       ],
   )
   ```
6. 默认包中只包含 Python 模块和包。为了包含额外文件，我们需要创建一个名为 `MANIFEST.in` 的文件。上一步中关于 setuptools 的文档详细介绍了这个文件。为了包含模板、`README.rst` 和我们的 `LICENSE` 文件，创建文件 `django-polls/MANIFEST.in` 包含以下内容：

   *django-polls/MANIFEST.in*

   ```text
   include LICENSE
   include README.rst
   recursive-include polls/static *
   recursive-include polls/templates *
   ```
7. 在应用中包含详细文档是可选的，但我们推荐你这样做。创建一个空目录 `django-polls/docs` 用于未来编写文档。额外添加一行至 `django-polls/MANIFEST.in`

   ```
   recursive-include docs *
   ```

   注意，现在 `docs` 目录不会被加入你的应用包，除非你往这个目录加几个文件。许多 Django 应用也提供他们的在线文档通过类似 [readthedocs.org](https://readthedocs.org) 这样的网站。
8. 试着构建你自己的应用包通过 `ptyhon setup.py sdist` （在 ```django-polls``目录内）。这将创建一个名为 ``dist``` 的目录并构建你自己的应用包， `django-polls-0.1.tar.gz`。

For more information on packaging, see Python's [Tutorial on Packaging and
Distributing Projects](https://packaging.python.org/tutorials/packaging-projects/).

## 使用你自己的包名

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

> **作为用户库安装**
>
> 以下步骤将 `django-polls` 以用户库的形式安装。与安装整个系统的软件包相比，用户安装具有许多优点，例如可在没有管理员访问权的系统上使用，以及防止应用包影响系统服务和其他用户。
>
> 注意，用户安装仍然会影响以这个用户身份运行的系统工具，所以 `virtualenv` 是一个更强大的解决方案（如下所示）。

1. 为了安装这个包，使用 pip (你早已 [安装 pip](#installing-reusable-apps-prerequisites), 对吗？):

   ```
   pip install --user django-polls/dist/django-polls-0.1.tar.gz
   ```
2. 幸运的话，你的 Django 项目应该再一次正确运行。启动服务器确认这一点。
3. 通过 pip 卸载包:

   ```
   pip uninstall django-polls
   ```

## 发布你的应用

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

- 通过邮件将你的包发送给朋友。
- 将这个包上传至你的网站。
- Post the package on a public repository, such as [the Python Package Index
  (PyPI)](#the-python-package-index-pypi). [packaging.python.org](https://packaging.python.org) has [a good
  tutorial](https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives)
  for doing this.

## 通过 virtualenv 安装 Python 包

早些时候，我们以用户库的形式安装了投票应用。这样做有一些缺点。

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

一般来说，这些状况只在你同时运行多个 Django 项目时出现。当这个问题出现时，最好的解决办法是使用 [virtualenv](https://virtualenv.pypa.io/)。这个工具允许你同时运行多个相互独立的Python环境，每个环境都有各自库和应用包命名空间的拷贝。
