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

This advanced tutorial begins where Tutorial 8 left off. We'll be turning our web-poll into a standalone Python package you can reuse in new projects and share with other people.

如果你尚未完成教程 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 包的处理流程。我知道,这可能会使你感到一点点迷惑。

你的项目和可复用应用

After the previous tutorials, our project should look like this:

mysite/
    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.gif
                style.css
        templates/
            polls/
                detail.html
                index.html
                results.html
        tests.py
        urls.py
        views.py
    templates/
        admin/
            base_site.html

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

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

安装必须环境

The current state of Python packaging is a bit muddled with various tools. For this tutorial, we're going to use setuptools to build our package. It's the recommended packaging tool (merged with the distribute fork). We'll also be using pip to install and uninstall it. You should install these two packages now. If you need help, you can refer to how to install Django with pip. You can install setuptools the same way.

打包你的应用

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

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

    为你的应用选择一个名字

    当为你的包选一个名字时,避免使用像 PyPI 这样已存在的包名,否则会导致冲突。当你创建你的发布包时,可以在模块名前增加 django- 前缀,这是一个很常用也很有用的避免包名冲突的方法。同时也有助于他人在寻找 Django 应用时确认你的 app 是 Django 独有的。

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

  2. polls 目录移入 django-polls 目录。

  3. 创建一个名为 django-polls/README.rst 的文件,包含以下内容:

    django-polls/README.rst
    =====
    Polls
    =====
    
    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 = [
            ...,
            "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. 接下来我们将创建 pyproject.tomlsetup.cfgsetup.py 文件,详细说明如何构建和安装该应用程序。对这些文件的全面解释超出了本教程的范围,但 setuptools 文档 有很好的解释。创建 django-polls/pyproject.tomldjango-polls/setup.cfgdjango-polls/setup.py 文件,内容如下:

    django-polls/pyproject.toml
    [build-system]
    requires = ['setuptools>=40.8.0']
    build-backend = 'setuptools.build_meta'
    
    django-polls/setup.cfg
    [metadata]
    name = django-polls
    version = 0.1
    description = A Django app to conduct web-based polls.
    long_description = file: README.rst
    url = https://www.example.com/
    author = Your Name
    author_email = yourname@example.com
    license = BSD-3-Clause  # Example license
    classifiers =
        Environment :: Web Environment
        Framework :: Django
        Framework :: Django :: X.Y  # Replace "X.Y" as appropriate
        Intended Audience :: Developers
        License :: OSI Approved :: BSD License
        Operating System :: OS Independent
        Programming Language :: Python
        Programming Language :: Python :: 3
        Programming Language :: Python :: 3 :: Only
        Programming Language :: Python :: 3.8
        Programming Language :: Python :: 3.9
        Topic :: Internet :: WWW/HTTP
        Topic :: Internet :: WWW/HTTP :: Dynamic Content
    
    [options]
    include_package_data = true
    packages = find:
    python_requires = >=3.8
    install_requires =
        Django >= X.Y  # Replace "X.Y" as appropriate
    
    django-polls/setup.py
    from setuptools import setup
    
    setup()
    
  6. 默认情况下,包中仅包含 Python 模块和包。 要包含其他文件,我们需要创建一个 MANIFEST.in 文件。 上一步中提到的 setuptools 文档更详细地讨论了这个文件。 要包含模板、README.rst 和我们的 LICENSE 文件,创建一个文件 django-polls/MANIFEST.in ,其内容如下:

    django-polls/MANIFEST.in
    include LICENSE
    include README.rst
    recursive-include polls/static *
    recursive-include polls/templates *
    
  7. It's optional, but recommended, to include detailed documentation with your app. Create an empty directory django-polls/docs for future documentation. Add an additional line to django-polls/MANIFEST.in:

    recursive-include docs *
    

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

  8. 试着用 python setup.py sdist 构建你的应用包(在 django-polls 目录运行)。这将创建一个名为 dist 的目录,并构建你的新应用包,django-polls-0.1.tar.gz

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

使用你自己的包名

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

作为用户库安装

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

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

  1. To install the package, use pip (you already installed it, right?):

    python -m pip install --user django-polls/dist/django-polls-0.1.tar.gz
    
  2. 幸运的话,你的 Django 项目应该再一次正确运行。启动服务器确认这一点。

  3. To uninstall the package, use pip:

    python -m pip uninstall django-polls
    

发布你的应用

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

通过虚拟环境安装 Python 包

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

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

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