{"title":"“站点”框架","version":"4.0","locale":"zh-hans","docname":"ref/contrib/sites","url":"/zh-hans/4.0/ref/contrib/sites/","canonical":"https://djangodocs.dev/zh-hans/4.0/ref/contrib/sites/","summary":"Django 自带了一个可选的“站点”框架。它是一个钩子，用于将对象和功能关联到特定的网站上，它是你的 Django 驱动的网站的域名和“啰嗦”名称的保存地。 如果你的单个 Django 安装支持多个站点，并且你需要以某种方式区分这些站点，那么就使用它。 站点框架主要基于这个模型： class models. Site…","html":"<span id=\"the-sites-framework\"></span><h1>“站点”框架<a class=\"heading-anchor\" href=\"#module-django.contrib.sites\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 自带了一个可选的“站点”框架。它是一个钩子，用于将对象和功能关联到特定的网站上，它是你的 Django 驱动的网站的域名和“啰嗦”名称的保存地。</p>\n<p>如果你的单个 Django 安装支持多个站点，并且你需要以某种方式区分这些站点，那么就使用它。</p>\n<p>站点框架主要基于这个模型：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.models.Site\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">Site</span></span><a class=\"heading-anchor\" href=\"#django.contrib.sites.models.Site\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>储存网站 <code class=\"docutils literal notranslate\"><span class=\"pre\">domain</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> 属性的模型。</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.models.Site.domain\">\n<span class=\"sig-name descname\"><span class=\"pre\">domain</span></span><a class=\"heading-anchor\" href=\"#django.contrib.sites.models.Site.domain\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>与网站相关的完全合格域名。例如，<code class=\"docutils literal notranslate\"><span class=\"pre\">www.example.com</span></code>。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.models.Site.name\">\n<span class=\"sig-name descname\"><span class=\"pre\">name</span></span><a class=\"heading-anchor\" href=\"#django.contrib.sites.models.Site.name\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>一个人类可读的“啰嗦”的网站名称。</p>\n</dd></dl>\n\n</dd></dl>\n\n<p><a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 配置指定与该特定配置文件相关联的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象的数据库 ID。如果省略该设置，则 <code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">get_current_site()</span></code> 函数将尝试通过比较 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site.domain\" title=\"django.contrib.sites.models.Site.domain\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">domain</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest.get_host\" title=\"django.http.HttpRequest.get_host\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">request.get_host()</span></code></a> 方法中的主机名来获取当前站点。</p>\n<p>如何使用这个功能由你决定，但 Django 通过几个约定自动使用它。</p>\n<section id=\"example-usage\">\n<h2>使用实例<a class=\"heading-anchor\" href=\"#example-usage\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>为什么要用站点？通过例子来解释是最好的。</p>\n<section id=\"associating-content-with-multiple-sites\">\n<h3>将内容与多个网站关联<a class=\"heading-anchor\" href=\"#associating-content-with-multiple-sites\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://www2.ljworld.com/\">LJWorld.com</a> 和 <a class=\"reference external\" href=\"http://www.lawrence.com/\">Lawrence.com</a> 网站由同一新闻组织——堪萨斯州劳伦斯市的《劳伦斯世界报》经营。LJWorld.com 专注于新闻，而 Lawrence.com 则专注于本地娱乐。但有时编辑们想 <em>同时</em> 在两个网站上发表一篇文章。</p>\n<p>解决这个问题的天真方法是要求网站制作者将同一篇报道发布两次：一次发布在 LJWorld.com，另一次发布在 Lawrence.com。但这对网站制作者来说效率很低，而且在数据库中存储同一故事的多个副本是多余的。</p>\n<p>更好的解决方案是去除内容重复。两个网站使用同一个文章数据库，一篇文章与一个或多个网站相关联。用 Django 模型术语来说，就是用 <code class=\"docutils literal notranslate\"><span class=\"pre\">Article</span></code> 模型中的一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ManyToManyField</span></code></a> 来表示：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Article</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">headline</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">)</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"n\">sites</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ManyToManyField</span><span class=\"p\">(</span><span class=\"n\">Site</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这就很好地完成了几件事：</p>\n<ul>\n<li><p>它让网站制作者可以在一个界面（Django 管理）上编辑两个网站的所有内容。</p></li>\n<li><p>这意味着同一个故事不必在数据库中发布两次，它在数据库中只有一条记录。</p></li>\n<li><p>它可以让网站开发者在两个网站上使用相同的 Django 视图代码。显示给定故事的视图代码会检查确认所请求的故事是否在当前站点上。它看起来像这样：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_current_site</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">article_detail</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">article_id</span><span class=\"p\">):</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">Article</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"n\">article_id</span><span class=\"p\">,</span> <span class=\"n\">sites__id</span><span class=\"o\">=</span><span class=\"n\">get_current_site</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"n\">Article</span><span class=\"o\">.</span><span class=\"n\">DoesNotExist</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"n\">Http404</span><span class=\"p\">(</span><span class=\"s2\">&quot;Article does not exist on this site&quot;</span><span class=\"p\">)</span>\n    <span class=\"c1\"># ...</span>\n</code></pre></div>\n</li>\n</ul>\n</section>\n<section id=\"associating-content-with-a-single-site\">\n<h3>将内容与单一网站关联<a class=\"heading-anchor\" href=\"#associating-content-with-a-single-site\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>同样，你也可以用 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 模型与 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code></a> 以多对一的关系关联。</p>\n<p>例如，如果一篇文章只允许在一个网站上发表，你会使用这样的模型：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Article</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">headline</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">)</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"n\">site</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Site</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这与上一节所述的好处相同。</p>\n</section>\n<section id=\"hooking-into-the-current-site-from-views\">\n<span id=\"hooking-into-current-site-from-views\"></span><h3>从视图连接到当前网站<a class=\"heading-anchor\" href=\"#hooking-into-the-current-site-from-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>你可以在你的 Django 视图中使用站点框架，根据视图被调用的站点来做特定的事情。例如：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.conf</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">settings</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">SITE_ID</span> <span class=\"o\">==</span> <span class=\"mi\">3</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do something.</span>\n        <span class=\"k\">pass</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do something else.</span>\n        <span class=\"k\">pass</span>\n</code></pre></div>\n<p>这样硬编码的网站 ID 很脆弱，万一变了呢。比较干净的方法是检查当前网站的域名：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_current_site</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"n\">current_site</span> <span class=\"o\">=</span> <span class=\"n\">get_current_site</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">current_site</span><span class=\"o\">.</span><span class=\"n\">domain</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;foo.com&#39;</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do something</span>\n        <span class=\"k\">pass</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do something else.</span>\n        <span class=\"k\">pass</span>\n</code></pre></div>\n<p>这样做的另一个好处是可以检查是否安装了站点框架，如果没有安装，则返回一个 <a class=\"reference internal\" href=\"#django.contrib.sites.requests.RequestSite\" title=\"django.contrib.sites.requests.RequestSite\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RequestSite</span></code></a> 实例。</p>\n<p>如果你没有访问请求对象的权限，你可以使用 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 模型的管理器的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_current()</span></code> 方法。然后你应该确保你的设置文件确实包含了 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 的配置。这个例子相当于前面的例子：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_function_without_request</span><span class=\"p\">():</span>\n    <span class=\"n\">current_site</span> <span class=\"o\">=</span> <span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">current_site</span><span class=\"o\">.</span><span class=\"n\">domain</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;foo.com&#39;</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do something</span>\n        <span class=\"k\">pass</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do something else.</span>\n        <span class=\"k\">pass</span>\n</code></pre></div>\n</section>\n<section id=\"getting-the-current-domain-for-display\">\n<h3>获取当前的显示域名<a class=\"heading-anchor\" href=\"#getting-the-current-domain-for-display\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>LJWorld.com 和 Lawrence.com 都有电子邮件提醒功能，让读者在新闻发生时注册以获得通知。这是很基本的：读者在一个网络表格上注册，并立即收到一封电子邮件说：“谢谢你的订阅”。</p>\n<p>如果把这个注册处理代码实现两次，那么效率就会很低，而且是多余的，所以各网站在后台使用的是相同的代码。但是“感谢您的注册”的通知需要每个网站都不一样。通过使用 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象，我们可以抽象出“感谢你”通知，使用当前站点的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site.name\" title=\"django.contrib.sites.models.Site.name\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">name</span></code></a> 和 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site.domain\" title=\"django.contrib.sites.models.Site.domain\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">domain</span></code></a> 的值。</p>\n<p>下面是表单处理视图的一个例子：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_current_site</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.mail</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">send_mail</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">register_for_newsletter</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Check form values, etc., and subscribe the user.</span>\n    <span class=\"c1\"># ...</span>\n\n    <span class=\"n\">current_site</span> <span class=\"o\">=</span> <span class=\"n\">get_current_site</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n    <span class=\"n\">send_mail</span><span class=\"p\">(</span>\n        <span class=\"s1\">&#39;Thanks for subscribing to </span><span class=\"si\">%s</span><span class=\"s1\"> alerts&#39;</span> <span class=\"o\">%</span> <span class=\"n\">current_site</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;Thanks for your subscription. We appreciate it.</span><span class=\"se\">\\n\\n</span><span class=\"s1\">-The </span><span class=\"si\">%s</span><span class=\"s1\"> team.&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span>\n            <span class=\"n\">current_site</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span>\n        <span class=\"p\">),</span>\n        <span class=\"s1\">&#39;editor@</span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"n\">current_site</span><span class=\"o\">.</span><span class=\"n\">domain</span><span class=\"p\">,</span>\n        <span class=\"p\">[</span><span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">email</span><span class=\"p\">],</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># ...</span>\n</code></pre></div>\n<p>在 Lawrence.com 上，这封邮件的主题是“感谢您订阅 Lawrence.com 的提醒”。在 LJWorld.com 上，这封邮件的主题是“感谢您订阅 LJWorld.com 的提醒”。邮件的信息主体也是如此。</p>\n<p>需要注意的是，一个更灵活（但更重量级）的方法是使用 Django 的模板系统。假设 Lawrence.com 和 LJWorld.com 有不同的模板目录（<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-TEMPLATES-DIRS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">DIRS</span></code></a>），你可以像这样向模板系统传递：</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.mail</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">send_mail</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.template</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">loader</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">register_for_newsletter</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Check form values, etc., and subscribe the user.</span>\n    <span class=\"c1\"># ...</span>\n\n    <span class=\"n\">subject</span> <span class=\"o\">=</span> <span class=\"n\">loader</span><span class=\"o\">.</span><span class=\"n\">get_template</span><span class=\"p\">(</span><span class=\"s1\">&#39;alerts/subject.txt&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">render</span><span class=\"p\">({})</span>\n    <span class=\"n\">message</span> <span class=\"o\">=</span> <span class=\"n\">loader</span><span class=\"o\">.</span><span class=\"n\">get_template</span><span class=\"p\">(</span><span class=\"s1\">&#39;alerts/message.txt&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">render</span><span class=\"p\">({})</span>\n    <span class=\"n\">send_mail</span><span class=\"p\">(</span><span class=\"n\">subject</span><span class=\"p\">,</span> <span class=\"n\">message</span><span class=\"p\">,</span> <span class=\"s1\">&#39;editor@ljworld.com&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">email</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># ...</span>\n</code></pre></div>\n<p>在这种情况下，你必须为 LJWorld.com 和 Lawrence.com 模板目录创建 <code class=\"file docutils literal notranslate\"><span class=\"pre\">subject.txt</span></code> 和 <code class=\"file docutils literal notranslate\"><span class=\"pre\">message.txt</span></code> 模板文件。这给你更多的灵活性，但也更复杂。</p>\n<p>尽量利用 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象是个好主意，以消除不必要的复杂性和冗余。</p>\n</section>\n<section id=\"getting-the-current-domain-for-full-urls\">\n<h3>获取当前域名的完整 URL<a class=\"heading-anchor\" href=\"#getting-the-current-domain-for-full-urls\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_absolute_url()`</span></code> 惯例对于获取对象的 URL（不含域名）是很好的，但在某些情况下，你可能想显示对象的完整 URL——包括 <code class=\"docutils literal notranslate\"><span class=\"pre\">http://</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=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">obj</span> <span class=\"o\">=</span> <span class=\"n\">MyModel</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">obj</span><span class=\"o\">.</span><span class=\"n\">get_absolute_url</span><span class=\"p\">()</span>\n<span class=\"go\">&#39;/mymodel/objects/3/&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">domain</span>\n<span class=\"go\">&#39;example.com&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"s1\">&#39;https://</span><span class=\"si\">%s%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">domain</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"o\">.</span><span class=\"n\">get_absolute_url</span><span class=\"p\">())</span>\n<span class=\"go\">&#39;https://example.com/mymodel/objects/3/&#39;</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"enabling-the-sites-framework\">\n<span id=\"id1\"></span><h2>启用站点框架<a class=\"heading-anchor\" href=\"#enabling-the-sites-framework\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>要启用站点框架，请按照以下步骤进行：</p>\n<ol class=\"arabic\">\n<li><p>将 <code class=\"docutils literal notranslate\"><span class=\"pre\">'django.contrib.sites'</span></code> 添加到你的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">INSTALLED_APPS</span></code></a> 配置中。</p></li>\n<li><p>定义一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 配置：</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\">SITE_ID</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n</code></pre></div>\n</li>\n<li><p>运行 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">migrate</span></code></a>。</p></li>\n</ol>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.sites</span></code> 注册了一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\"><span class=\"pre\">post_migrate</span></code></a> 信号处理程序，该处理程序创建了一个名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">example.com</span></code> 的默认站点，域名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">example.com</span></code>。这个站点也将在 Django 创建测试数据库后被创建。要为你的项目设置正确的名称和域名，你可以使用一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/migrations/#data-migrations\"><span class=\"std std-ref\">数据迁移</span></a>。</p>\n<p>为了在生产中为不同的站点提供服务，你会为每个 <code class=\"docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code> 创建一个单独的配置文件（也许是从一个通用的配置文件中导入，以避免重复的共享设置），然后为每个站点指定适当的 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">:envar:`DJANGO_SETTINGS_MODULE`</span></a>。</p>\n</section>\n<section id=\"caching-the-current-site-object\">\n<h2>缓存当前 <code class=\"docutils literal notranslate\"><span class=\"pre\">Site</span></code> 对象<a class=\"heading-anchor\" href=\"#caching-the-current-site-object\"><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\">Site.objects.get_current()</span></code> 都可能导致数据库查询。但 Django 比这更聪明：在第一次请求时，当前站点会被缓存，随后的任何调用都会返回缓存的数据，而不是打到数据库。</p>\n<p>如果你出于任何原因想要强制查询数据库，你可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">Site.objects.clear_cache()</span></code> 告诉 Django 清除缓存：</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=\"c1\"># First call; current site fetched from database.</span>\n<span class=\"n\">current_site</span> <span class=\"o\">=</span> <span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span>\n<span class=\"c1\"># ...</span>\n\n<span class=\"c1\"># Second call; current site fetched from cache.</span>\n<span class=\"n\">current_site</span> <span class=\"o\">=</span> <span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span>\n<span class=\"c1\"># ...</span>\n\n<span class=\"c1\"># Force a database query for the third call.</span>\n<span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">clear_cache</span><span class=\"p\">()</span>\n<span class=\"n\">current_site</span> <span class=\"o\">=</span> <span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span>\n</code></pre></div>\n</section>\n<section id=\"the-currentsitemanager\">\n<h2><code class=\"docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code><a class=\"heading-anchor\" href=\"#the-currentsitemanager\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.managers.CurrentSiteManager\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">managers.</span></span><span class=\"sig-name descname\"><span class=\"pre\">CurrentSiteManager</span></span><a class=\"heading-anchor\" href=\"#django.contrib.sites.managers.CurrentSiteManager\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 在你的应用中起着关键作用，请考虑在你的模型中使用有用的 <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code>。它是一个模型 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/db/managers/\"><span class=\"doc\">管理器</span></a>，可以自动过滤查询，只包含与当前 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 相关的对象。</p>\n<aside class=\"admonition-mandatory-setting-site-id admonition\">\n<p class=\"admonition-title\">强制性 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a></p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code> 只有在你的配置中定义了 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 配置时才能使用。</p>\n</aside>\n<p>使用 <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.managers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CurrentSiteManager</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Photo</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">photo</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">FileField</span><span class=\"p\">(</span><span class=\"n\">upload_to</span><span class=\"o\">=</span><span class=\"s1\">&#39;photos&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">photographer_name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">pub_date</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n    <span class=\"n\">site</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Site</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Manager</span><span class=\"p\">()</span>\n    <span class=\"n\">on_site</span> <span class=\"o\">=</span> <span class=\"n\">CurrentSiteManager</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>在这种模式下，<code class=\"docutils literal notranslate\"><span class=\"pre\">Photo.objects.all()</span></code> 将返回数据库中的所有 <code class=\"docutils literal notranslate\"><span class=\"pre\">Photo</span></code> 对象，但 <code class=\"docutils literal notranslate\"><span class=\"pre\">Photo.on_site.all()</span></code> 将根据 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 设置，只返回与当前站点相关的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Photo</span></code> 对象。</p>\n<p>换个角度看，这两种说法是等价的：</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\">Photo</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">site</span><span class=\"o\">=</span><span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">SITE_ID</span><span class=\"p\">)</span>\n<span class=\"n\">Photo</span><span class=\"o\">.</span><span class=\"n\">on_site</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">()</span>\n</code></pre></div>\n<p><a class=\"reference internal\" href=\"#django.contrib.sites.managers.CurrentSiteManager\" title=\"django.contrib.sites.managers.CurrentSiteManager\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code></a> 怎么知道 <code class=\"docutils literal notranslate\"><span class=\"pre\">Photo</span></code> 的哪个字段是 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a>？默认情况下， <a class=\"reference internal\" href=\"#django.contrib.sites.managers.CurrentSiteManager\" title=\"django.contrib.sites.managers.CurrentSiteManager\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code></a> 会寻找一个名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">site</span></code> 的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code></a> 或者一个名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">sites</span></code> 的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ManyToManyField</span></code></a> 来进行过滤。如果你使用一个名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">site</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">sites</span></code> 以外的字段来识别你的对象与哪些 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象相关，那么你需要显式地将自定义字段名作为参数传递给你的模型上的 <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code>。下面的模型，它有一个叫做 <code class=\"docutils literal notranslate\"><span class=\"pre\">publish_on</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.managers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CurrentSiteManager</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Photo</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">photo</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">FileField</span><span class=\"p\">(</span><span class=\"n\">upload_to</span><span class=\"o\">=</span><span class=\"s1\">&#39;photos&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">photographer_name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">pub_date</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n    <span class=\"n\">publish_on</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Site</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Manager</span><span class=\"p\">()</span>\n    <span class=\"n\">on_site</span> <span class=\"o\">=</span> <span class=\"n\">CurrentSiteManager</span><span class=\"p\">(</span><span class=\"s1\">&#39;publish_on&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你试图使用 <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code> 并传递一个不存在的字段名，Django 将引发一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValueError</span></code>。</p>\n<p>最后，请注意，你可能会希望在你的模型上保留一个正常的（非特定站点的）``Manager``，即使你使用 <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code>。正如 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/db/managers/\"><span class=\"doc\">管理器文档</span></a> 中解释的那样，如果你手动定义一个管理器，那么 Django 不会自动为你创建 <code class=\"docutils literal notranslate\"><span class=\"pre\">objects</span> <span class=\"pre\">=</span> <span class=\"pre\">models.Manager()</span></code> 管理器。另外要注意的是，Django 的某些部分——即 Django 的管理站点和通用视图——使用模型中 <em>先</em> 定义的管理器，所以如果你想让你的管理站点能够访问所有的对象（不仅仅是站点特定的对象），请在定义 <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CurrentSiteManager</span></code> 之前，把 <code class=\"docutils literal notranslate\"><span class=\"pre\">objects</span> <span class=\"pre\">=</span> <span class=\"pre\">models.Manager()</span></code> 放在你的模型中。</p>\n</section>\n<section id=\"site-middleware\">\n<span id=\"id2\"></span><h2>站点中间件<a class=\"heading-anchor\" href=\"#site-middleware\"><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=\"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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.sites.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Site</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"n\">site</span> <span class=\"o\">=</span> <span class=\"n\">Site</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_current</span><span class=\"p\">()</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>为了避免重复，在 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> 中添加 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/middleware/#django.contrib.sites.middleware.CurrentSiteMiddleware\" title=\"django.contrib.sites.middleware.CurrentSiteMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.contrib.sites.middleware.CurrentSiteMiddleware</span></code></a>。中间件会在每个请求对象上设置 <code class=\"docutils literal notranslate\"><span class=\"pre\">site</span></code> 属性，所以你可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">request.site</span></code> 来获取当前站点。</p>\n</section>\n<section id=\"how-django-uses-the-sites-framework\">\n<h2>Django 如何使用站点框架<a class=\"heading-anchor\" href=\"#how-django-uses-the-sites-framework\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>虽然不要求你使用站点框架，但强烈鼓励你使用，因为 Django 在一些地方利用了它。即使你的 Django 只安装了一个站点，你也应该花两秒钟的时间用你的 <code class=\"docutils literal notranslate\"><span class=\"pre\">domain</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> 创建站点对象，并在你的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 配置中指向它的 ID。</p>\n<p>下面是 Django 如何使用站点框架：</p>\n<ul class=\"simple\">\n<li><p>在 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/redirects/#module-django.contrib.redirects\" title=\"django.contrib.redirects: A framework for managing redirects.\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">重定向框架</span></code></a> 中，每个重定向对象都与一个特定的站点相关联。当 Django 搜索一个重定向时，它会考虑到当前的站点。</p></li>\n<li><p>在 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/flatpages/#module-django.contrib.flatpages\" title=\"django.contrib.flatpages: A framework for managing simple ?flat? HTML content in a database.\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">简单页面框架</span></code></a> 中，每个简单页面都与一个特定的站点相关联。当创建一个简单页面时，你指定它的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/flatpages/#django.contrib.flatpages.middleware.FlatpageFallbackMiddleware\" title=\"django.contrib.flatpages.middleware.FlatpageFallbackMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">FlatpageFallbackMiddleware</span></code></a> 在检索要显示的简单页面时检查当前站点。</p></li>\n<li><p>在 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/syndication/#module-django.contrib.syndication\" title=\"django.contrib.syndication: A framework for generating syndication feeds, in RSS and Atom, quite easily.\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">聚合框架</span></code></a> 中，<code class=\"docutils literal notranslate\"><span class=\"pre\">title</span></code> 和 description` 的模板会自动访问一个变量 <code class=\"docutils literal notranslate\"><span class=\"pre\">{{</span> <span class=\"pre\">site</span> <span class=\"pre\">}}</span></code>，它是代表当前站点的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象。另外，如果你没有指定一个完全限定的域，提供项目 URL 的钩子将使用当前 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象中的 <code class=\"docutils literal notranslate\"><span class=\"pre\">domain</span></code>。</p></li>\n<li><p>在 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/#module-django.contrib.auth\" title=\"django.contrib.auth: Django's authentication framework.\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">认证框架</span></code></a> 中， <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/default/#django.contrib.auth.views.LoginView\" title=\"django.contrib.auth.views.LoginView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.views.LoginView</span></code></a> 将当前 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 名称作为 <code class=\"docutils literal notranslate\"><span class=\"pre\">{{</span> <span class=\"pre\">site_name</span> <span class=\"pre\">}}</span></code> 传递给模板。</p></li>\n<li><p>便捷工具视图（<code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.contenttypes.views.shortcut</span></code>）在计算对象的 URL 时，使用当前 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象的域名。</p></li>\n<li><p>在管理框架中，“在站点上查看”链接使用当前的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 来计算出它将重定向到的站点的域名。</p></li>\n</ul>\n</section>\n<section id=\"requestsite-objects\">\n<h2><code class=\"docutils literal notranslate\"><span class=\"pre\">RequestSite</span></code> 对象<a class=\"heading-anchor\" href=\"#requestsite-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p id=\"id3\">有些 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/\"><span class=\"doc\">django.contrib</span></a> 应用程序利用了站点框架的优势，但其架构方式并不 <em>要求</em> 在数据库中安装网站框架。(有些人不想，或者只是不 <em>能</em> 安装额外的数据库表，而这是网站框架所要求的。) 对于这些情况，框架提供了一个 <a class=\"reference internal\" href=\"#django.contrib.sites.requests.RequestSite\" title=\"django.contrib.sites.requests.RequestSite\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.contrib.sites.requests.RequestSite</span></code></a> 类，当数据库支持的站点框架不可用时，它可以作为后备。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.requests.RequestSite\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">requests.</span></span><span class=\"sig-name descname\"><span class=\"pre\">RequestSite</span></span><a class=\"heading-anchor\" href=\"#django.contrib.sites.requests.RequestSite\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>一个共享 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 的主要接口的类（即它有 <code class=\"docutils literal notranslate\"><span class=\"pre\">domain</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> 属性），但它的数据是从 Django <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 对象而不是数据库中获取的。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.requests.RequestSite.__init__\">\n<span class=\"sig-name descname\"><span class=\"pre\">__init__</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">request</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sites.requests.RequestSite.__init__\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>将 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">domain</span></code> 属性配置为 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest.get_host\" title=\"django.http.HttpRequest.get_host\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">get_host()</span></code></a> 的值。</p>\n</dd></dl>\n\n</dd></dl>\n\n<p>一个 <a class=\"reference internal\" href=\"#django.contrib.sites.requests.RequestSite\" title=\"django.contrib.sites.requests.RequestSite\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RequestSite</span></code></a> 对象的接口与普通的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象类似，只是它的 <a class=\"reference internal\" href=\"#django.contrib.sites.requests.RequestSite.__init__\" title=\"django.contrib.sites.requests.RequestSite.__init__\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">__init__()</span></code></a> 方法采用了一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 对象。它能够通过查看请求的域名来推断出 <code class=\"docutils literal notranslate\"><span class=\"pre\">domain</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code>。它有 <code class=\"docutils literal notranslate\"><span class=\"pre\">save()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">delete()</span></code> 方法，与 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 的接口相匹配，但这些方法会引发 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#NotImplementedError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">NotImplementedError</span></code></a>。</p>\n</section>\n<section id=\"get-current-site-shortcut\">\n<h2><code class=\"docutils literal notranslate\"><span class=\"pre\">get_current_site</span></code> 便捷工具<a class=\"heading-anchor\" href=\"#get-current-site-shortcut\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>最后，为了避免重复的回退代码，框架提供了一个 <a class=\"reference internal\" href=\"#django.contrib.sites.shortcuts.get_current_site\" title=\"django.contrib.sites.shortcuts.get_current_site\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">django.contrib.sites.shortcuts.get_current_site()</span></code></a> 函数。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sites.shortcuts.get_current_site\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">shortcuts.</span></span><span class=\"sig-name descname\"><span class=\"pre\">get_current_site</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">request</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sites.shortcuts.get_current_site\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>一个检查是否安装了 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.sites</span></code> 的函数，并根据请求返回当前的 <a class=\"reference internal\" href=\"#django.contrib.sites.models.Site\" title=\"django.contrib.sites.models.Site\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Site</span></code></a> 对象或一个 <a class=\"reference internal\" href=\"#django.contrib.sites.requests.RequestSite\" title=\"django.contrib.sites.requests.RequestSite\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RequestSite</span></code></a> 对象。如果没有定义 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SITE_ID\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SITE_ID</span></code></a> 的配置，它就会根据 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest.get_host\" title=\"django.http.HttpRequest.get_host\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">request.get_host()</span></code></a> 来查找当前站点。</p>\n<p>当主机头有一个明确指定的端口时，例如 <code class=\"docutils literal notranslate\"><span class=\"pre\">example.com:80</span></code>，域名和端口都可能被 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest.get_host\" title=\"django.http.HttpRequest.get_host\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">request.get_host()</span></code></a> 返回。在这种情况下，如果因为主机与数据库中的记录不匹配而导致查找失败，那么端口将被剥离，并且只用域名部分重新进行查找。这不适用于 <a class=\"reference internal\" href=\"#django.contrib.sites.requests.RequestSite\" title=\"django.contrib.sites.requests.RequestSite\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RequestSite</span></code></a>，它将始终使用未修改的主机。</p>\n</dd></dl>\n\n</section>","rootId":"module-django.contrib.sites","toc":[{"title":"使用实例","anchor":"example-usage","children":[{"title":"将内容与多个网站关联","anchor":"associating-content-with-multiple-sites","children":[]},{"title":"将内容与单一网站关联","anchor":"associating-content-with-a-single-site","children":[]},{"title":"从视图连接到当前网站","anchor":"hooking-into-the-current-site-from-views","children":[]},{"title":"获取当前的显示域名","anchor":"getting-the-current-domain-for-display","children":[]},{"title":"获取当前域名的完整 URL","anchor":"getting-the-current-domain-for-full-urls","children":[]}]},{"title":"启用站点框架","anchor":"enabling-the-sites-framework","children":[]},{"title":"缓存当前 Site 对象","anchor":"caching-the-current-site-object","children":[]},{"title":"CurrentSiteManager","anchor":"the-currentsitemanager","children":[]},{"title":"站点中间件","anchor":"site-middleware","children":[]},{"title":"Django 如何使用站点框架","anchor":"how-django-uses-the-sites-framework","children":[]},{"title":"RequestSite 对象","anchor":"requestsite-objects","children":[]},{"title":"get_current_site 便捷工具","anchor":"get-current-site-shortcut","children":[]}],"breadcrumbs":[{"docname":"ref/index","title":"API 参考","url":"/zh-hans/4.0/ref/"},{"docname":"ref/contrib/index","title":"contrib 包","url":"/zh-hans/4.0/ref/contrib/"}],"prev":{"docname":"ref/contrib/sitemaps","title":"站点地图框架","url":"/zh-hans/4.0/ref/contrib/sitemaps/"},"next":{"docname":"ref/contrib/staticfiles","title":"staticfiles 应用","url":"/zh-hans/4.0/ref/contrib/staticfiles/"},"formats":{"html":"/zh-hans/4.0/ref/contrib/sites/","markdown":"/zh-hans/4.0/ref/contrib/sites.md","json":"/zh-hans/4.0/ref/contrib/sites.json"},"source":"https://github.com/django/django/blob/stable/4.0.x/docs/ref/contrib/sites.txt","official":"https://docs.djangoproject.com/zh-hans/4.0/ref/contrib/sites/","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","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}