Django 官网最新 Tutorial 渣翻 - Part 8(进阶教程)

上一节:Django 官网最新 Tutorial 渣翻 - Part 7

进阶教程:如何编写可重用的应用程序

这个进阶教程上接 Tutorial 7。 我们将把我们的网页投票转换成一个独立的Python包,这样你可以在其它项目中重用或者分享给其它人。

如果您最近没有完成教程1-7,我们建议您先看他们,以使您的示例项目与下面描述的项目相匹配。

可重用性很重要

设计、构建、测试和维护一个网页应用有许多工作要做。 许多Python 和 Django 项目都有常见的共同问题。 可重用将会节省这些重复性工作。

可重用性在Python 中是一种常见的方式。 Python包索引 (PyPI) 具有广泛的包,你可以在你自己的Python程序中使用。 查阅一下Django 包 中已经存在的可重用的应用,你可以结合它们到你的项目。 Django 自身也只是一个Python 包。 这意味着你可以获取已经存在的Python包和Django应用并将它们融合到你自己的网页项目。 你只需要编写你项目的独特的部分。

假设您正在开始一个新项目,需要一个像我们一直在进行的投票应用程序。 你如何让该应用可重用? 幸运的是,你已经在正确的道路上。 在 Tutorial 3中,我们看到我们可以如何使用include将投票应用从项目级别的URLconf 解耦。 在本教程中,我们将更进一步,让你的应用在新的项目中容易地使用并随时可以发布给其它人安装和使用。

包? 应用?
Python 按照简单重用的方式,将具有相关性的Python代码归为一组。 一个包包含一个或多个Python文件(也叫做“模块”)。
包可以通过import foo.barfrom foo import bar 导入。 如果一个目录(例如polls)想要形成一个包,它必须包含一个特殊的文件__init__.py,即使这个文件为空。
一个Django 应用 只是一个Python包,它特意用于Django项目中。 一个应用可以使用常见的Django 约定,例如具有urlstestsmodelsviews 子模块。
后面我们使用打包这个词来描述将一个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

你在 Tutorial 3Tutorial 7中创建了polls/templatesmysite/templates。 现在你可能更加清晰为什么我们为项目和应用选择单独的模板目录:属于投票应用的部分全部在polls中。 它使得该应用“自包含(self-contained)”且更加容易丢到一个新的项目中。

现在可以拷贝polls目录到一个新的Django项目并立即重用。 尽管它还不能充分准备好到可以立即发布。 所以,我们需要打包这个应用来让它对其他人易于安装。

安装一些先决条件

Python 打包的目前状态因为有多种工具而混乱不堪。 对于本教程,我们打算使用setuptools来构建我们的包。 它是推荐的打包工具(已经与distribute 分支合并)。 我们还将使用pip来安装和卸载它。 现在你应该安装这两个包。 如果你需要帮助,你可以参考 how to install Django with pip。 你可以使用同样的方法安装setuptools


打包您的应用程序

Python 打包 会将你的应用预处理成一种特殊的格式, 这样安装和使用就会变得简单。 Django 自己是以非常相似的方式打包起来的。 对于一个像polls这样的小应用,这个过程不是太难。

  1. 首先,在你的Django项目之外,为polls创建一个父目录。 称这个目录为django-polls。

为你的应用选择一个名字
当为你的包选择一个名字时,检查一下PyPI中的资源以避免与已经存在的包有名字冲突。 当创建一个要发布的包时,在你的模块名字前面加上django-通常很有用。 这有助于其他正在查找Django应用的人区分你的应用是专门用于Django的。
应用程序标签(即应用程序包的虚线路径的最后一部分)必须INSTALLED_APPS中是唯一的。 避免使用与Django的contrib 包 中任何一个使用相同的标签,例如adminauthmessages

  1. 将polls 目录移动到django-polls目录中。

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

django-polls/README.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.
  1. 创建一个django-polls/LICENSE文件。 如何选择License超出本教程的范围,但值得一说的是, 公开发布的代码如果没有License是毫无用处的。 Django和许多Django兼容的应用程序是根据BSD许可证分发的;但是,您可以自由选择自己的许可证。 只需知道你所选择的License,将决定谁能使用你的代码.

  2. 下一步我们将创建一个setup.py 文件,它提供如何构建和安装该应用的详细信息。 该文件完整的解释超出本教程的范围,setuptools 文档 有很好的解释。 创建一个文件django-polls/setup.py,其内容如下:

django-polls/setup.py

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',
    ],
)
  1. 默认只有Python模块和包会包含进包中。 如果需要包含额外的文件,我们需要创建一个MANIFEST.in文件。 上一步提到的setuptools 文档对这个文件有更详细的讨论。 如果要包含模板、django-polls/MANIFEST.in和我们的LICENSE 文件,创建一个文件README.rst,其内容如下:
django-polls/MANIFEST.in

include LICENSE
include README.rst
recursive-include polls/static *
recursive-include polls/templates *
  1. 这是可选的,但建议您在应用程序中包含详细的文档。 创建一个空目录django-polls/docs以供将来使用。 向django-polls/MANIFEST.in添加另外一行:
recursive-include docs *

注意docs不会包含进你的包中除非你添加一些文件到它下面。 许多Django应用还通过类似readthedocs.org这样的站点提供它们的在线文档.

  1. 试着通过python setup.py sdist 构建你的包(从django-polls的内部运行)。 这会创建一个django-polls-0.1.tar.gz目录并构建一个新包:dist。

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


使用你自己的包

因为,我们将polls 目录移到项目的目录之外,它不再工作了。 我们将通过安装我们的新的django-polls包来修复它。

安装成某个用户的库
以下的步骤将安装django-polls 成某个用户的库。 用户级别的安装比系统级别的安装有许多优点,例如将包运行在普通用户级别上不但不会影响系统服务还不会影响其他用户
注意根据用户的安装仍然可以影响以该用户身份运行的系统工具,所以virtualenv 是更健壮的解决办法(见下文)。

  1. 要安装软件包,请使用pip(您已经installed it,对吧?):
pip install --user django-polls/dist/django-polls-0.1.tar.gz
  1. 幸运的话,你的Django 项目现在应该又能正常工作了。 请重新运行服务器以证实这点。

  2. 若要卸载这个包,使用pip:

pip uninstall django-polls

发布您的应用程序

既然我们已经打包并测试过django-polls,是时候与世界共享它了! 如果它不仅仅是个例子,你现在可以:


使用 virtualenv 安装Python包

前面,我们将poll 安装成一个用户的库。 它有一些缺点:

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

特别是一旦你维护几个Django项目,这些情况就会出现。 如果确实出现,最好的解决办法是使用virtualenv。 这个工具允许你维护多个分离的Python环境,每个都具有它自己的库和包的命名空间。