{"title":"进阶指南：如何编写可重用程序","version":"5.2","locale":"zh-hans","docname":"intro/reusable-apps","url":"/zh-hans/5.2/intro/reusable-apps/","canonical":"https://djangodocs.dev/zh-hans/5.2/intro/reusable-apps/","summary":"这个进阶教程从 教程第 8 部分 结束的地方继续讲起。我们将会把我们的网络投票应用放进一个独立的 Python 包中，以便你在新的项目中重用它或将它与他人分享。 如果你最近没有完成教程 1-8，我们鼓励你回顾这些内容，以便你的示例项目与下面描述的项目相匹配。 可重用性很重要 Link to this heading #…","html":"<h1>进阶指南：如何编写可重用程序<a class=\"heading-anchor\" href=\"#advanced-tutorial-how-to-write-reusable-apps\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>这个进阶教程从 <a class=\"reference internal\" href=\"/zh-hans/5.2/intro/tutorial08/\"><span class=\"doc\">教程第 8 部分</span></a>  结束的地方继续讲起。我们将会把我们的网络投票应用放进一个独立的 Python 包中，以便你在新的项目中重用它或将它与他人分享。</p>\n<p>如果你最近没有完成教程 1-8，我们鼓励你回顾这些内容，以便你的示例项目与下面描述的项目相匹配。</p>\n<section id=\"reusability-matters\">\n<h2>可重用性很重要<a class=\"heading-anchor\" href=\"#reusability-matters\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>设计，构建，测试以及维护一个 web 应用要做很多的工作。很多 Python 以及 Django 项目都有一些常见问题。如果我们能保存并利用这些重复的工作岂不是更好？</p>\n<p>可重用性是 Python 的根本。<a class=\"reference external\" href=\"https://pypi.python.org/pypi\">The Python Package Index (PyPI)</a> 有许大量的包，都可被用在你自己的 Python 项目中。同样可以在 <a class=\"reference external\" href=\"https://djangopackages.org\">Django Packages</a> 中查找已发布的可重用应用，也可将其引入到你的项目中。Django 本身也是一个 Python 包，也就是说你可以将已有的 Python 包或 Django 应用并入你的项目。你只需要编写属于你的那部分即可。</p>\n<p>假设你现在创建了一个新的项目，并且需要一个类似我们之前做的投票应用。你该如何复用这个应用呢？庆幸的是，其实你已经知道了一些。在 <a class=\"reference internal\" href=\"/zh-hans/5.2/intro/tutorial01/\"><span class=\"doc\">教程 1</span></a>，我们使用过 <code class=\"docutils literal notranslate\"><span class=\"pre\">include</span></code> 从项目级别的 URLconf 分割出 polls。在本教程中，我们将进一步使这个应用易用于新的项目中，并发布给其他人安装使用。</p>\n<aside class=\"admonition-package-app admonition\">\n<p class=\"admonition-title\">包？应用？</p>\n<p>一个 <a class=\"reference external\" href=\"https://docs.python.org/3/glossary.html#term-package\" title=\"(in Python v3.14)\"><span class=\"xref std std-term\">package</span></a> 提供了一组关联的 Python 代码的简单复用方式。一个包（“模块”）包含了一个或多个 Python 代码文件。</p>\n<p>一个包通过 <code class=\"docutils literal notranslate\"><span class=\"pre\">import</span> <span class=\"pre\">foo.bar</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">from</span> <span class=\"pre\">foo</span> <span class=\"pre\">import</span> <span class=\"pre\">bar</span></code> 的形式导入。一个目录（例如 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code>）要成为一个包，它必须包含一个特定的文件 <code class=\"docutils literal notranslate\"><span class=\"pre\">__init__.py</span></code>，即便这个文件是空的。</p>\n<p>Django <em>应用</em> 仅仅是专用于 Django 项目的 Python 包。应用会按照 Django 规则，创建好 <code class=\"docutils literal notranslate\"><span class=\"pre\">models</span></code>,  <code class=\"docutils literal notranslate\"><span class=\"pre\">tests</span></code>,  <code class=\"docutils literal notranslate\"><span class=\"pre\">urls</span></code>, 以及 <code class=\"docutils literal notranslate\"><span class=\"pre\">views</span></code> 等子模块。</p>\n<p>稍后，我们将解释术语 <em>打包</em> ——为了方便其它人安装 Python 包的处理流程。我知道，这可能会使你感到一点点迷惑。</p>\n</aside>\n</section>\n<section id=\"your-project-and-your-reusable-app\">\n<h2>你的项目和可复用应用<a class=\"heading-anchor\" href=\"#your-project-and-your-reusable-app\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>通过前面的教程，我们的工程应该看起来像这样:</p>\n<div class=\"code-block\" data-language=\"text\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Text</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Text code\"><code>djangotutorial/\n    manage.py\n    mysite/\n        __init__.py\n        settings.py\n        urls.py\n        asgi.py\n        wsgi.py\n    polls/\n        __init__.py\n        admin.py\n        apps.py\n        migrations/\n            __init__.py\n            0001_initial.py\n        models.py\n        static/\n            polls/\n                images/\n                    background.png\n                style.css\n        templates/\n            polls/\n                detail.html\n                index.html\n                results.html\n        tests.py\n        urls.py\n        views.py\n    templates/\n        admin/\n            base_site.html\n</code></pre></div>\n<p>你在 <a class=\"reference internal\" href=\"/zh-hans/5.2/intro/tutorial07/\"><span class=\"doc\">教程 7</span></a> 中创建了 <code class=\"docutils literal notranslate\"><span class=\"pre\">djangotutorial/templates</span></code>，在 <a class=\"reference internal\" href=\"/zh-hans/5.2/intro/tutorial03/\"><span class=\"doc\">教程 3</span></a> 中创建了 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/templates</span></code>。现在可能更清楚为什么我们选择为项目和应用程序分别设置独立的模板目录了：所有属于 polls 应用程序的内容都放在 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> 中。这使得应用程序自包含，并且更容易移植到新项目中。</p>\n<p>目录 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> 现在可以被拷贝至一个新的 Django 工程，且立刻被复用。不过现在还不是发布它的时候。为了这样做，我们需要打包这个应用，便于其他人安装它。</p>\n</section>\n<section id=\"installing-some-prerequisites\">\n<span id=\"installing-reusable-apps-prerequisites\"></span><h2>安装必须环境<a class=\"heading-anchor\" href=\"#installing-some-prerequisites\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Python 包装的当前状态有些混乱，有各种各样的工具。对于本教程，我们将使用 <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/setuptools/\">setuptools</a> 来构建我们的包。它是推荐的打包工具（与 <code class=\"docutils literal notranslate\"><span class=\"pre\">distribute</span></code> 分支合并）。我们还将使用 <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/pip/\">pip</a> 来安装和卸载它。你现在应该安装这两个包。如果你需要帮助，可以参考 <a class=\"reference internal\" href=\"/zh-hans/5.2/topics/install/#installing-official-release\"><span class=\"std std-ref\">如何使用 pip 安装 Django</span></a>。你可以以相同的方式安装 <code class=\"docutils literal notranslate\"><span class=\"pre\">setuptools</span></code>。</p>\n</section>\n<section id=\"packaging-your-app\">\n<h2>打包你的应用<a class=\"heading-anchor\" href=\"#packaging-your-app\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Python 的 <em>打包</em> 将以一种特殊的格式组织你的应用，意在方便安装和使用这个应用。Django 本身就被打包成类似的形式。对于一个小应用，例如 polls，这不会太难。</p>\n<ol class=\"arabic\">\n<li><p>首先，在 Django 项目之外创建一个父目录来存放包。将该目录命名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code>。</p>\n<aside class=\"admonition-choosing-a-name-for-your-app admonition\">\n<p class=\"admonition-title\">为你的应用选择一个名字</p>\n<p>选择软件包名称时，请在 PyPI 上检查以避免与现有软件包命名冲突。我们建议为软件包名称使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-</span></code> 前缀，以标识你的软件包特定于 Django，并为你的模块名称使用相应的 <code class=\"docutils literal notranslate\"><span class=\"pre\">django_</span></code> 前缀。例如，<code class=\"docutils literal notranslate\"><span class=\"pre\">django-ratelimit</span></code> 软件包包含 <code class=\"docutils literal notranslate\"><span class=\"pre\">django_ratelimit</span></code> 模块。</p>\n<p>应用标签（指用点分隔的包名的最后一部分）在 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">INSTALLED_APPS</span></code></a> 中 <em>必须</em> 是独一无二的。避免使用任何与 Django <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/contrib/\"><span class=\"doc\">contrib packages</span></a> 文档中相同的标签名，比如 <code class=\"docutils literal notranslate\"><span class=\"pre\">auth</span></code>，<code class=\"docutils literal notranslate\"><span class=\"pre\">admin</span></code>，<code class=\"docutils literal notranslate\"><span class=\"pre\">messages</span></code>。</p>\n</aside>\n</li>\n<li><p>将 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> 目录移动到 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code> 目录中，并将其重命名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">django_polls</span></code>。</p></li>\n<li><p>编辑 <code class=\"docutils literal notranslate\"><span class=\"pre\">django_polls/apps.py</span></code>，使 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/applications/#django.apps.AppConfig.name\" title=\"django.apps.AppConfig.name\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">name</span></code></a> 指向新的模块名称，并添加 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/applications/#django.apps.AppConfig.label\" title=\"django.apps.AppConfig.label\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">label</span></code></a> 以为应用程序提供一个简短的名称：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/django_polls/apps.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.apps</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">AppConfig</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">PollsConfig</span><span class=\"p\">(</span><span class=\"n\">AppConfig</span><span class=\"p\">):</span>\n    <span class=\"n\">default_auto_field</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;django.db.models.BigAutoField&quot;</span>\n    <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;django_polls&quot;</span>\n    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;polls&quot;</span>\n</code></pre></figure>\n</li>\n<li><p>创建一个名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/README.rst</span></code> 的文件，包含以下内容：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"rst\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/README.rst</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Rst</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Rst code\"><code><span class=\"gh\">============</span>\n<span class=\"gh\">django-polls</span>\n<span class=\"gh\">============</span>\n\ndjango-polls is a Django app to conduct web-based polls. For each\nquestion, visitors can choose between a fixed number of answers.\n\nDetailed documentation is in the &quot;docs&quot; directory.\n\n<span class=\"gh\">Quick start</span>\n<span class=\"gh\">-----------</span>\n\n<span class=\"m\">1.</span> Add &quot;polls&quot; to your INSTALLED_APPS setting like this::\n\n    INSTALLED_APPS = [\n<span class=\"c\">        ...,</span>\n<span class=\"c\">        &quot;django_polls&quot;,</span>\n<span class=\"c\">    ]</span>\n\n<span class=\"m\">2.</span> Include the polls URLconf in your project urls.py like this::\n\n    path(&quot;polls/&quot;, include(&quot;django_polls.urls&quot;)),\n\n<span class=\"m\">3.</span> Run <span class=\"s\">``python manage.py migrate``</span> to create the models.\n\n<span class=\"m\">4.</span> Start the development server and visit the admin to create a poll.\n\n<span class=\"m\">5.</span> Visit the <span class=\"s\">``/polls/``</span> URL to participate in the poll.\n</code></pre></figure>\n</li>\n<li><p>创建一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/LICENSE</span></code> 文件。选择一个非本教程使用的授权协议，但是要足以说明发布代码没有授权证书是 <em>不可能的</em> 。Django 和很多兼容 Django 的应用是以 BSD 授权协议发布的；不过，你可以自己选择一个授权协议。只要确定你选择的协议能够限制未来会使用你的代码的人。</p></li>\n<li><p>接下来我们将创建 <code class=\"docutils literal notranslate\"><span class=\"pre\">pyproject.toml</span></code> 文件，该文件详细说明了如何构建和安装应用程序。对这个文件的完整解释超出了本教程的范围，但 <a class=\"reference external\" href=\"https://packaging.python.org/guides/writing-pyproject-toml/\">Python 打包用户指南</a> 提供了很好的解释。创建 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/pyproject.toml</span></code> 文件，内容如下：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"toml\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/pyproject.toml</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Toml</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Toml code\"><code><span class=\"k\">[build-system]</span>\n<span class=\"n\">requires</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"p\">[</span><span class=\"s2\">&quot;setuptools&gt;83&quot;</span><span class=\"p\">]</span>\n<span class=\"n\">build-backend</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;setuptools.build_meta&quot;</span>\n\n<span class=\"k\">[project]</span>\n<span class=\"n\">name</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;django-polls&quot;</span>\n<span class=\"n\">version</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;0.1&quot;</span>\n<span class=\"n\">dependencies</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"p\">[</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;django&gt;=X.Y&quot;</span><span class=\"p\">,</span><span class=\"w\">  </span><span class=\"c1\"># Replace &quot;X.Y&quot; as appropriate</span>\n<span class=\"p\">]</span>\n<span class=\"n\">description</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;A Django app to conduct web-based polls.&quot;</span>\n<span class=\"n\">readme</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;README.rst&quot;</span>\n<span class=\"n\">license</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;BSD-3-Clause&quot;</span>\n<span class=\"n\">requires-python</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;&gt;= 3.10&quot;</span>\n<span class=\"n\">authors</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"p\">[</span>\n<span class=\"w\">    </span><span class=\"p\">{</span><span class=\"n\">name</span><span class=\"w\"> </span><span class=\"p\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;Your Name&quot;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">email</span><span class=\"w\"> </span><span class=\"p\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;yourname@example.com&quot;</span><span class=\"p\">},</span>\n<span class=\"p\">]</span>\n<span class=\"n\">classifiers</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"p\">[</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Environment :: Web Environment&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Framework :: Django&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Framework :: Django :: X.Y&quot;</span><span class=\"p\">,</span><span class=\"w\">  </span><span class=\"c1\"># Replace &quot;X.Y&quot; as appropriate</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Intended Audience :: Developers&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Operating System :: OS Independent&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3 :: Only&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3.10&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3.11&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3.12&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3.13&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Programming Language :: Python :: 3.14&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Topic :: Internet :: WWW/HTTP&quot;</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"s2\">&quot;Topic :: Internet :: WWW/HTTP :: Dynamic Content&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n\n<span class=\"k\">[project.urls]</span>\n<span class=\"n\">Homepage</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"s2\">&quot;https://www.example.com/&quot;</span>\n</code></pre></figure>\n</li>\n<li><p>默认情况下，许多常见文件和 Python 模块及包已经包含在包中。要包含额外的文件，我们需要创建一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">MANIFEST.in</span></code> 文件。为了包含模板和静态文件，创建一个文件 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/MANIFEST.in</span></code>，内容如下：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"text\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/MANIFEST.in</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Text</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Text code\"><code>recursive-include django_polls/static *\nrecursive-include django_polls/templates *\n</code></pre></figure>\n</li>\n<li><p>虽然不是必须的，但建议为你的应用程序包含详细的文档。创建一个空目录 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls/docs</span></code> 以便将来存放文档。</p>\n<p>注意，现在 <code class=\"docutils literal notranslate\"><span class=\"pre\">docs</span></code> 目录不会被加入你的应用包，除非你往这个目录加几个文件。许多 Django 应用也提供他们的在线文档通过类似 <a class=\"reference external\" href=\"https://readthedocs.org\">readthedocs.org</a> 这样的网站。</p>\n<p>Many Python projects, including Django and Python itself, use <a class=\"reference external\" href=\"https://www.sphinx-doc.org/en/master/usage/quickstart.html\">Sphinx</a> to build\ntheir documentation. If you choose to use Sphinx you can link back to the\nDjango documentation by configuring <a class=\"reference external\" href=\"https://www.sphinx-doc.org/en/master/usage/quickstart.html#intersphinx\">Intersphinx</a>\nand including a value for Django in your project's <code class=\"docutils literal notranslate\"><span class=\"pre\">intersphinx_mapping</span></code>\nvalue:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">intersphinx_mapping</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"s2\">&quot;django&quot;</span><span class=\"p\">:</span> <span class=\"p\">(</span>\n        <span class=\"s2\">&quot;https://docs.djangoproject.com/en/stable/&quot;</span><span class=\"p\">,</span>\n        <span class=\"kc\">None</span><span class=\"p\">,</span>\n    <span class=\"p\">),</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>With that in place, you can then cross-link to specific entries, in the\nsame way as in the Django docs, such as\n&quot;<code class=\"docutils literal notranslate\"><span class=\"pre\">:attr:`django.test.TransactionTestCase.databases`</span></code>&quot;.</p>\n</li>\n<li><p>Check that the <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/build/\">build</a> package is installed (<code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span>\n<span class=\"pre\">build</span></code>) and try building your package by running <code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">build</span></code> inside\n<code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code>. This creates a directory called <code class=\"docutils literal notranslate\"><span class=\"pre\">dist</span></code> and builds your\nnew package into source and binary formats, <code class=\"docutils literal notranslate\"><span class=\"pre\">django_polls-0.1.tar.gz</span></code> and\n<code class=\"docutils literal notranslate\"><span class=\"pre\">django_polls-0.1-py3-none-any.whl</span></code>.</p></li>\n</ol>\n<p>更多关于打包的信息，见 Python 的 <a class=\"reference external\" href=\"https://packaging.python.org/tutorials/packaging-projects/\">关于打包和发布项目的教程</a>。</p>\n</section>\n<section id=\"using-your-own-package\">\n<h2>使用你自己的包名<a class=\"heading-anchor\" href=\"#using-your-own-package\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>由于我们把 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> 目录移出了项目，所以它无法工作了。我们现在要通过安装我们的新 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code> 应用来修复这个问题。</p>\n<aside class=\"admonition-installing-as-a-user-library admonition\">\n<p class=\"admonition-title\">作为用户库安装</p>\n<p>以下步骤将 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code> 以用户库的形式安装。与安装整个系统的软件包相比，用户安装具有许多优点，例如可在没有管理员访问权的系统上使用，以及防止应用包影响系统服务和其他用户。</p>\n<p>请注意，按用户安装仍然会影响以该用户身份运行的系统工具的行为，因此使用虚拟环境是更可靠的解决方案（请参见下文）。</p>\n</aside>\n<ol class=\"arabic\">\n<li><p>为了安装这个包，使用 pip (你早已 <a class=\"reference internal\" href=\"#installing-reusable-apps-prerequisites\"><span class=\"std std-ref\">安装 pip</span></a>, 对吗？):</p>\n<div class=\"code-block\" data-language=\"shell\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code>python<span class=\"w\"> </span>-m<span class=\"w\"> </span>pip<span class=\"w\"> </span>install<span class=\"w\"> </span>--user<span class=\"w\"> </span>django-polls/dist/django_polls-0.1.tar.gz\n</code></pre></div>\n</li>\n<li><p>更新 <code class=\"docutils literal notranslate\"><span class=\"pre\">mysite/settings.py</span></code> 以指向新的模块名称：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">INSTALLED_APPS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django_polls.apps.PollsConfig&quot;</span><span class=\"p\">,</span>\n    <span class=\"o\">...</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n</li>\n<li><p>更新 <code class=\"docutils literal notranslate\"><span class=\"pre\">mysite/urls.py</span></code> 以指向新的模块名称：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s2\">&quot;polls/&quot;</span><span class=\"p\">,</span> <span class=\"n\">include</span><span class=\"p\">(</span><span class=\"s2\">&quot;django_polls.urls&quot;</span><span class=\"p\">)),</span>\n    <span class=\"o\">...</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n</li>\n<li><p>运行开发服务器以确认项目继续工作。</p></li>\n</ol>\n</section>\n<section id=\"publishing-your-app\">\n<h2>发布你的应用<a class=\"heading-anchor\" href=\"#publishing-your-app\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>现在，你已经对 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code> 完成了打包和测试，准备好向世界分享它！如果这不是一个例子应用，你现在就可以这样做。</p>\n<ul class=\"simple\">\n<li><p>通过邮件将你的包发送给朋友。</p></li>\n<li><p>将这个包上传至你的网站。</p></li>\n<li><p>将你的包发布至公共仓库，比如 <a class=\"reference external\" href=\"https://pypi.python.org/pypi\">the Python Package Index (PyPI)</a>。 <a class=\"reference external\" href=\"https://packaging.python.org\">packaging.python.org</a> 有一个不错的 <a class=\"reference external\" href=\"https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives\">教程</a> 说明如何发布至公共仓库。</p></li>\n</ul>\n</section>\n<section id=\"installing-python-packages-with-a-virtual-environment\">\n<h2>通过虚拟环境安装 Python 包<a class=\"heading-anchor\" href=\"#installing-python-packages-with-a-virtual-environment\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>早些时候，我们将 <code class=\"docutils literal notranslate\"><span class=\"pre\">django-polls</span></code> 安装为用户库。这样做有一些不利之处：</p>\n<ul class=\"simple\">\n<li><p>修改用户库会影响你系统上的其他 Python 软件。</p></li>\n<li><p>你将不能运行此包的多个版本（或者其它用有相同包名的包）。</p></li>\n</ul>\n<p>通常，只有在维护多个 Django 项目时才会出现这些情况。当这样做时，最好的解决方法是使用 <a class=\"reference external\" href=\"https://docs.python.org/3/tutorial/venv.html\" title=\"(in Python v3.14)\"><span class=\"xref std std-doc\">venv</span></a>。使用此工具，你可以维护多个隔离的 Python 环境，每个环境都有其自己的库和包命名空间的副本。</p>\n</section>","rootId":"advanced-tutorial-how-to-write-reusable-apps","toc":[{"title":"可重用性很重要","anchor":"reusability-matters","children":[]},{"title":"你的项目和可复用应用","anchor":"your-project-and-your-reusable-app","children":[]},{"title":"安装必须环境","anchor":"installing-some-prerequisites","children":[]},{"title":"打包你的应用","anchor":"packaging-your-app","children":[]},{"title":"使用你自己的包名","anchor":"using-your-own-package","children":[]},{"title":"发布你的应用","anchor":"publishing-your-app","children":[]},{"title":"通过虚拟环境安装 Python 包","anchor":"installing-python-packages-with-a-virtual-environment","children":[]}],"breadcrumbs":[{"docname":"intro/index","title":"开始","url":"/zh-hans/5.2/intro/"}],"prev":{"docname":"intro/tutorial08","title":"编写你的第一个 Django 应用程序，第 8 部分","url":"/zh-hans/5.2/intro/tutorial08/"},"next":{"docname":"intro/whatsnext","title":"下一步看什么","url":"/zh-hans/5.2/intro/whatsnext/"},"formats":{"html":"/zh-hans/5.2/intro/reusable-apps/","markdown":"/zh-hans/5.2/intro/reusable-apps.md","json":"/zh-hans/5.2/intro/reusable-apps.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/intro/reusable-apps.txt","official":"https://docs.djangoproject.com/zh-hans/5.2/intro/reusable-apps/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}