You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django项目中实现多区域多语言的内容版本?

实现Django「语言+区域」双层路由与内容定制方案

技术名称

这种实现方式属于多维度本地化路由(Multi-dimensional Localization Routing),核心是在语言前缀基础上增加区域维度的URL捕获与内容过滤,和Django官网的「语言+版本」路由逻辑完全一致。


分步实现方法

1. 重构URL路由结构

在现有i18n路由基础上,新增区域前缀的捕获规则:

# project/urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
from .views import redirect_to_default_region

urlpatterns = [
    path('admin/', admin.site.urls),
]

# 扩展i18n路由,加入区域前缀
urlpatterns += i18n_patterns(
    # 匹配「语言/区域/」开头的路径
    path('<str:region>/', include('blog.urls')),
    # 处理无区域前缀的请求,重定向到默认区域
    path('', redirect_to_default_region),
)

对应的重定向视图:

# project/views.py
from django.conf import settings
from django.http import HttpResponseRedirect

def redirect_to_default_region(request):
    default_region = getattr(settings, 'DEFAULT_REGION', 'glo')
    lang_code = request.LANGUAGE_CODE
    return HttpResponseRedirect(f'/{lang_code}/{default_region}/')

2. 自定义区域中间件

将区域信息绑定到request对象,并支持通过session记住用户选择的区域:

# project/middleware.py
from django.conf import settings
from django.http import HttpResponseRedirect

class RegionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.default_region = getattr(settings, 'DEFAULT_REGION', 'glo')
        self.allowed_regions = getattr(settings, 'ALLOWED_REGIONS', ['glo', 'us', 'eu'])

    def __call__(self, request):
        # 从URL解析区域
        path_parts = request.path.lstrip('/').split('/')
        if len(path_parts) >=2 and path_parts[1] in self.allowed_regions:
            request.region = path_parts[1]
        else:
            # 优先从session取,无则用默认
            request.region = request.session.get('region', self.default_region)
            lang_code = path_parts[0] if path_parts else settings.LANGUAGE_CODE
            return HttpResponseRedirect(f'/{lang_code}/{request.region}/')
        
        # 存入session,维持用户选择
        request.session['region'] = request.region

        response = self.get_response(request)
        return response

在settings.py中注册中间件(放在LocaleMiddleware之后):

MIDDLEWARE = [
    # ...其他中间件
    'django.middleware.locale.LocaleMiddleware',
    'project.middleware.RegionMiddleware',
]

# 新增区域配置
ALLOWED_REGIONS = ['glo', 'us', 'eu']
DEFAULT_REGION = 'glo'

3. 适配django-parler的区域内容过滤

给文章模型新增区域字段,在视图中基于当前区域过滤内容:

# blog/models.py
from django.db import models
from parler.models import TranslatableModel, TranslatedFields

class Post(TranslatableModel):
    translations = TranslatedFields(
        title=models.CharField(max_length=200),
        content=models.TextField(),
    )
    # 区域字段:glo=全球,us=美国,eu=欧盟
    region = models.CharField(
        max_length=3,
        choices=[('glo', 'Global'), ('us', 'US'), ('eu', 'EU')],
        default='glo'
    )
    # 其他字段...

视图中过滤查询集:

# blog/views.py
from django.views.generic import ListView
from .models import Post
from django.db.models import Q

class PostListView(ListView):
    model = Post
    template_name = 'blog/post_list.html'

    def get_queryset(self):
        # 显示当前区域内容 + 全球通用内容
        return super().get_queryset().filter(
            Q(region=self.request.region) | Q(region='glo')
        )

4. 实现语言+区域选择菜单

在模板中添加选择器,语言选择复用Django i18n标签,区域选择生成对应URL:

<!-- templates/base.html -->
{% load i18n %}

<!-- 语言选择器 -->
<form action="{% url 'set_language' %}" method="post">
    {% csrf_token %}
    <input name="next" type="hidden" value="{{ request.path }}">
    <select name="language" onchange="this.form.submit()">
        {% get_current_language as LANGUAGE_CODE %}
        {% get_available_languages as LANGUAGES %}
        {% get_language_info_list for LANGUAGES as languages %}
        {% for lang in languages %}
            <option value="{{ lang.code }}" {% if lang.code == LANGUAGE_CODE %}selected{% endif %}>
                {{ lang.name_local }} ({{ lang.code }})
            </option>
        {% endfor %}
    </select>
</form>

<!-- 区域选择器 -->
<div class="region-selector">
    {% with current_region=request.region %}
        <a href="/{{ LANGUAGE_CODE }}/glo/" {% if current_region == 'glo' %}class="active"{% endif %}>Global</a>
        <a href="/{{ LANGUAGE_CODE }}/us/" {% if current_region == 'us' %}class="active"{% endif %}>US</a>
        <a href="/{{ LANGUAGE_CODE }}/eu/" {% if current_region == 'eu' %}class="active"{% endif %}>EU</a>
    {% endwith %}
</div>

关键注意事项

  • 确保ALLOWED_REGIONS配置的区域代码和URL中的捕获值完全一致
  • 若需要区域专属的配置(如时区、支付方式),可在settings.py中新增REGION_SETTINGS字典存储
  • 可扩展区域模型到数据库,支持后台动态管理区域配置

内容的提问来源于stack exchange,提问作者mdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:53:16