Joh*_*ann 0 django country routes url-routing region
我正在将一个电子商务网站转换为特定于区域(例如美国、欧盟)的网站,因此根据访问者将看到的内容,它基本上会感觉像是一个不同的网站,即使它实际上是一个网站(对于许多人来说)原因)。我网站上的大多数路径都将成为特定于区域的路径,通过在路径开头添加区域前缀,例如“/us/”(我可以转换所有路径,但如果它使它变得更加容易的话)。
我的计划:
中间件根据 1) 请求路径、2) 会话或 3) 根据 IP 地址的顺序猜测来识别区域,并将其设置在请求对象上。此外,一旦他们使用区域路径,它就会存储为会话值。通过这种方式,区域上下文可以跨非区域特定的 URL 传递。
特定于区域的 URL 模式必须更新以匹配区域,即使我已经在中间件中检测到该区域,因为逻辑比路径更复杂。尽管如此,出于下一个原因(反向),我必须将其作为参数并传递到我的所有视图中。此外,任何变为区域性的路径都将使其先前的模式301重定向到其区域性路径。
为了生成特定于区域的链接,我必须通过添加区域参数来更新对 reverse() 和 {% url %} 的许多调用。我希望这里有一些层可以自定义,以便在了解请求的情况下动态反转 URL。
我的主要问题是处理逆转的最佳方法(最后一个项目符号)。感觉像是做了很多不必要的工作。我愿意接受更好的方法来解决整体问题。
更新:
我想出了几种方法可以做到这一点(第四种是使用子域的好处)。所有这些都假设有一个中间件来检测区域并根据请求进行设置。
按照 @RemcoGerlich 的提示,模仿 Django 如何处理 URL 国际化。LocaleMiddleware检测语言并设置该请求的活动语言(使用线程局部变量)。然后,该活动语言用于通过 i18n_patterns() 形成 URL,它实际上返回 a LocaleRegexURLResolver(它是普通解析器的子类)而不是 url。我相信可以做类似的事情来支持其他类型的前缀。
更强力的方法是不仅将区域存储在请求中,而且再次存储在线程局部变量中,就像 Django 对活动语言所做的那样。更新 URL 以具有区域前缀的命名参数并添加到视图参数。实现自定义反向以添加区域参数。如果想要作恶,可以对其进行猴子修补,以避免触及每个单个reverse和url模板引用。
使用中间件根据区域设置,以覆盖request.urlconfROOT_URLCONF. 这仅为该请求提供了一组完全不同的 URL。每个区域创建一个新的 URLconf,添加其前缀,然后包含基本 URLconf。无需捕获路径的区域部分或弄乱视图参数。反转 URL“正常”。
如果您想使用子域(我没有),则有一个名django-hosts为此问题中引用的 Django 应用程序:Django: Overwrite ROOT_URLCONF with request.urlconf in middleware。
对于我的应用程序来说,使用request.urlconf中间件覆盖是最简单、最优雅的解决方案。这是中间件的一个片段:
# ... detect region first based on path, then session, and and maybe later IP address...
# Then force the URLconf:
if request.region == Region.EU:
request.urlconf = "mysite.regional_urls.eu_urls"
else:
request.urlconf = "mysite.regional_urls.us_urls"
Run Code Online (Sandbox Code Playgroud)
我为每个区域创建了一个新的 URLconf,但它们都是枯燥的单行:
urlpatterns = create_patterns_for_region(Region.EU)
Run Code Online (Sandbox Code Playgroud)
这些引用了一个模板,该模板将我想要成为区域性的 URL 与我想要保留“裸露”的 URL 组合在一起:
from django.conf.urls import patterns, include, url
def create_patterns_for_region(region):
return patterns(
'',
# First match regional.
url(r'^{}/'.format(region.short), include('mysite.regional_urls.regional_base_urls')),
# Non-regional pages.
url(r'', include('mysite.regional_urls.nonregional_base_urls')),
# Any regional URL is missing.
url(r'^{}/.*'.format(Region.REGION_PREFIX), error_views.Custom404.as_error_view()),
# Attempt to map any non-regional URL to region for backward compatibility.
url(r'.*', RegionRedirect.as_view()),
)
Run Code Online (Sandbox Code Playgroud)
最后是用于向后兼容的重定向视图:
class RegionRedirect(RedirectView):
""" Map paths without region to regional versions for backward compatibility.
"""
permanent = True
query_string = True
def get_redirect_url(self, *args, **kwargs):
self.url = "/" + self.request.region.short + self.request.path
return super(RegionRedirect, self).get_redirect_url(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
确保更新缓存以包含区域。;)
| 归档时间: |
|
| 查看次数: |
1117 次 |
| 最近记录: |