简体   繁体   English

django SITE_ID 通过查询

[英]django SITE_ID by query

I have a django app.我有一个 django 应用程序。 I'm adding a second site.我正在添加第二个站点。

So now I need to set SITE_ID correctly.所以现在我需要正确设置 SITE_ID。 This is easy enough, except that since it is the primary key id in the Site table, this means the value is dependent on the order in which sites have been added (and, eventually, deleted).这很容易,除了因为它是 Site 表中的主键 id,这意味着该值取决于添加(并最终删除)站点的顺序。 That's fragile, without even discussing how developers will sort this if they've done any scratch work in that table.这很脆弱,甚至没有讨论如果开发人员在该表中做了任何临时工作,他们将如何对其进行排序。 Much better to set it by query.通过查询设置它要好得多。

SITE_ID = Site.objects.get(name='my_site_name').id

But the settings_myapp.py file, which sets WSGI_APPLICATION , is pretty much the only one that might know which app I'm running.但是设置WSGI_APPLICATIONsettings_myapp.py文件几乎是唯一可能知道我正在运行哪个应用程序的文件。 I could try modifying settings in that site-specific settings file, but importing settings at that point leads to an error that SECRET_KEY is not yet defined.我可以尝试修改该站点特定settings文件中的设置,但此时导入设置会导致SECRET_KEY尚未定义的错误。

Is there a robust way to do this?有没有一种强大的方法来做到这一点?

This is a summary of how I solved the problem I stated in my question.这是我如何解决我在问题中陈述的问题的总结。 Unbeknownst to me when I asked the question, there are actually several facets demanding different approaches.当我问这个问题时,我并不知道,实际上有几个方面需要不同的方法。

A bit of middleware helps enormously for deployed instances (ie, not dev).一点中间件对已部署的实例(即,不是开发实例)有很大帮助。 This solution provides a django 3.1 ready code snippet, as a solution that existed in times past is no longer compatible with modern django.此解决方案提供了 django 3.1 就绪代码片段,因为过去存在的解决方案不再与现代 django 兼容。

For developers, I added this to my settings.py :对于开发人员,我将其添加到我的settings.py

DEFAULT_SITE_ID = os.getenv('DEFAULT_SITE_ID')

And so the snippet above becomes this:所以上面的代码片段变成了这样:

class DynamicSiteDomainMiddleware:
    default_site_id = None

    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.
        self.default_site_id = settings.DEFAULT_SITE_ID
        if self.default_site_id is not None:
            current_site = Site.objects.get(id=self.default_site_id)

    def __call__(self, request):
        if self.default_site_id is None:
            try:
                current_site = Site.objects.get(domain=request.get_host())
            except Site.DoesNotExist:
                current_site = Site.objects.get(id=settings.DEFAULT_SITE_ID)
        else:
            current_site = Site.objects.get(id=self.default_site_id)

        request.current_site = current_site
        settings.SITE_ID = current_site.id

        response = self.get_response(request)
        return response

In other words, if a developer has set DEFAULT_SITE_ID (eg, on the commandline when invoking manage.py ) that value is used.换句话说,如果开发人员已设置DEFAULT_SITE_ID (例如,在调用manage.py时在命令行上),则使用该值。 Otherwise, we look at SNI on requests.否则,我们会根据请求查看 SNI。

This leaves one bit of the puzzle unanswered: what to do about urlpatterns ?这留下了一个未解之谜:如何处理urlpatterns I've two sites (soon three) that have slightly different URL schemes.我有两个站点(很快三个),它们的 URL 方案略有不同。 But in the main urls.py , the site information is not yet available under this clever middleware solution, as urlpatterns is (naturally and necessarily) set before any requests happen.但是在主urls.py中,站点信息在这个聪明的中间件解决方案下尚不可用,因为 urlpatterns (自然且必然)在任何请求发生之前设置。

The approach that smells best to me sets an environment variables so that settings.py can set ROOT_URLCONF for its specific case.对我来说最好闻的方法设置环境变量,以便settings.py可以为其特定情况设置ROOT_URLCONF

ROOT_URLCONF = os.getenv('ROOT_URLCONF', 'transport_nantes.urls_tn')

An apparent disadvantage is that we end up stuck with two incompatible mechanisms for setting the site data: DEFAULT_SITE_ID + SNI and also ROOT_URLCONF .一个明显的缺点是我们最终遇到了两种不兼容的设置站点数据的机制: DEFAULT_SITE_ID + SNI 和ROOT_URLCONF This isn't as bad as it seems, however, since these are two independent aspects of the problem: what site I am and what URL scheme I mean to have.然而,这并不像看起来那么糟糕,因为这是问题的两个独立方面:我是什么站点以及我打算拥有的 URL 方案。 This required a very small change to production and staging deployment code to set the appropriate environment variable.这需要对生产和暂存部署代码进行非常小的更改以设置适当的环境变量。

Finally, in each of the url_XYZ.py files, I set a variable for the base template for that version of the site.最后,在每个url_XYZ.py文件中,我为该版本网站的基本模板设置了一个变量。 (At issue is that the links are different. If it were just changing the logo, it would be easier.) I pass that value in a dict to the included url files, and so I can use that knowledge when rendering views, even though view functions are often shared amongst several sites and URL schemes. (问题在于链接不同。如果只是更改徽标,那会更容易。)我将字典中的值传递给包含的 url 文件,因此我可以在渲染视图时使用该知识,即使视图功能通常在多个站点和 URL 方案之间共享。

So why not set an environment variable for the SITE_ID as well?那么为什么不也为SITE_ID设置一个环境变量呢? This goes back to the initial question: the site id is fragile, being the primary key in the sites table.这又回到了最初的问题:站点 id 是脆弱的,它是站点表中的主键。 It is reasonable to imagine some bit of maintenance that leaves the sites table unchanged except for a changed primary key (for example, an inadvertent deletion followed by recreation of the record).可以合理地想象一些维护会使站点表保持不变,除了更改的主键(例如,无意删除然后重新创建记录)。 So looking up values by name is more robust.因此,按名称查找值更加健壮。

On the other hand, the ROOT_URLCONF variable has the advantage that it's not tied to the sites table.另一方面, ROOT_URLCONF变量的优点是它绑定到站点表。 For example, site X has a certain URL scheme, which is true whether X is running in production or staging or testing, all of which have different FQDN's.例如,站点 X 有一个特定的 URL 方案,无论 X 是在生产中运行还是在暂存或测试中运行,都是如此,所有这些都有不同的 FQDN。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM