如何在Django URL模式中捕获子域名?

7
我有一个支持多种语言的Django应用程序。我想添加子域名支持,以便访问“de.mysite.com”时查询德语文章,“mysite.com”查询英语内容(默认语言)。大约会有20个子域名都指向同一个Django应用。
我有一个抽象模型,其中包含所有数据字段和每种语言的派生模型。每种语言都有自己的数据库表,如下所示:
class ArticleBase(models.Model):
    title = models.CharField(max_length=240, unique=True)
    date_added = models.DateField(auto_now_add=True)

    class Meta:
        abstract = True

# This is English, the default.
class Article(ArticleBase):
    pass

class Article_de(ArticleBase):
    pass

我可以获取像这样的文章(我今天已经做到了):
def article(request, title, language=None):
    if language:
        mod = get_model('app', 'Article_' + language)
        items = mod.filter(title=title)
    else:
        items = Article.objects.filter(title=title)

这是我当前的URL模式:

url(r'^article/(?P<title>[a-zA-Z_-]+)/$", 'app.views.article', name='article'),

我该如何解析URL模式中的子域前缀,以便将其传递到文章视图中?或者在处理视图时,我应该从请求中获取此信息吗?
3个回答

10

Django中的URLS无法访问URL的域部分,因此这不是一个选项。 在每个视图中手动完成是可行的,但不易于维护。

我认为自定义中间件解决方案可能更好,您可以在中间件中检查请求标头,然后加载适当的语言(或替换accept-language标头,让Django完成其工作)

{{link1:localemiddleware}}可以使语言可用,您可以轻松地将其用于传递到所需的模型/查询中。

另外,如果我可以问一下:为什么要将每个条目存储在单独的表/模型中?您不能只向模型添加语言字段并将所有内容存储在一个表中吗?因为对于文章等20个左右的模型而言,选择多个模型可能比选择一个模型更难以维护。

更新:

我已经进行了一些测试,发现所需的中间件非常简单(尽管我的测试非常有限):

class SubDomainLanguage(object):
    def process_request(self, request):
        try:
            request.session['django_language'] = request.META['HTTP_HOST'].split('.')[0]
        except KeyError:
            pass

是中间件,然后更改设置以包括以下内容:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'subdomainmiddleware.SubDomainLanguage',
    'django.middleware.locale.LocaleMiddleware',
    ...
)

这样,您就可以利用正常的Django内置i18n支持。

在视图中,语言将可用于request.LANGUAGE_CODE


谢谢,这是一个很好的解决方案。我正在处理分布在不同位置的几个服务器上的大量数据,并通过语言进行分区,以保持查询时间并让我将不同的东西放在不同的服务器上并通过DNS路由 - 目前一个服务器用于en / es,一个用于de / fr / pt,另一个用于“其他语言”。 :) - Jason Champion

0

我有一个问题,我的子域名中包含点号,例如1.2.3.mydomain.net。我知道我的域名并在local_settings.py中设置了它:

DOMAIN = 'EXAMPLE.net'
TEST_SUBDOMAINS = ["127.0.0.1", "localhost", "testserver"]

然后我检查一下,如果是为了测试目的,我就不做任何事情。 之后,我按照以下方式获取我的子域:

if (DOMAIN in TEST_SUBDOMAINS):
    return HttpResponse("test only")
subdomain = request.META['HTTP_HOST'].replace((DOMAIN), "")[:-1] 
# -1 is to remove the trailing "." from the subdomain
if subdomain and subdomain != "www" :
# whatever you need...

0

您可以使用这个易于使用的django-subdomains库。它还支持基于子域名的URL路由和反向解析。


该库已不再维护。 - C. Ardayfio
请参考 https://github.com/LeeHanYeong/django-subdomains2#quick-start在settings.py中添加SUBDOMAIN_DOMAIN,并加入与django-subdomains相同的设置:将'subdomains.middleware.SubdomainURLRoutingMiddleware'添加到MIDDLEWARE中。添加/保留ROOT_URLCONFSUBDOMAIN_URLCONFS。可选地,在INSTALLED_APPS中添加/保留'subdomains'。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接