django 中的动态 url 路由
Dynamic url routing in django
我有一个 RoutingUrl 模型,它描述了我站点上使用的所有 urls 以及必须管理 url 和一些其他路由信息的视图(视图模型的外键) . url 的大小在不断增加,应该也支持重定向。型号大致如下:
class RoutingUrl(models.Model):
url = models.CharField(unique=True, verbose_name='routing url')
crc_checksum = models.IntegerField(editable=False)
redirect_to = models.ForeignKey('RoutingUrl', related_name='redirect_from', blank=True, null=True)
view = models.ForeignKey(View, related_name='routing_urls')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class View(models.Model):
name = models.CharField()
RoutingUrl 也有一个通用外键,模型包含有关要呈现的页面的信息(必须支持不同的模型,这就是通用外键的原因)。
现在的问题是:如何在django中实现这样的动态路由?我的感觉是我有两个选择:
- 我可以创建一个中间件,它将通过实施 process_request 方法(在检查 url 模式之前)负责将请求分派到正确的视图。显然这样的中间件应该位于中间件堆栈的底部,以保持其他中间件的功能。因此,该解决方案将绕过 Django 路由系统。
- 另一种选择是添加一个 catch all url 匹配所有内容的模式,然后只编写我自己的 handler/dispatcher 作为视图。该处理程序实现路由过程,因此将调用适当的视图和 return 它的 HttpResponse
你能建议我这两个选项中哪一个最适合实现这样的路由吗?当然,如果有第三种更好的选择,请不要犹豫向我推荐。
稍微调查一下 django 中间件挂钩,很明显 process_request 不是实现路由功能的最佳选择。事实上,从文档中:
It should return either None or an HttpResponse object. If it returns
None, Django will continue processing this request, executing any
other process_request() middleware, then, process_view() middleware,
and finally, the appropriate view. If it returns an HttpResponse
object, Django won’t bother calling any other request, view or
exception middleware, or the appropriate view; it’ll apply response
middleware to that HttpResponse, and return the result.
所以 HttpResponse 会破坏中间件堆栈功能。 process_view 大致相同,这将避免异常中间件的调用。此时采用第二种方案似乎更明智...
django-cms 插件证实了这种直觉,正如您可以从 urlpatterns 定义的 source code 中看到的那样:
from django.conf import settings
from django.conf.urls import url
from cms.apphook_pool import apphook_pool
from cms.appresolver import get_app_patterns
from cms.views import details
# This is a constant, really, but must live here due to import order
SLUG_REGEXP = '[0-9A-Za-z-_.//]+'
if settings.APPEND_SLASH:
regexp = r'^(?P<slug>%s)/$' % SLUG_REGEXP
else:
regexp = r'^(?P<slug>%s)$' % SLUG_REGEXP
if apphook_pool.get_apphooks():
# If there are some application urls, use special resolver,
# so we will have standard reverse support.
urlpatterns = get_app_patterns()
else:
urlpatterns = []
urlpatterns.extend([
url(regexp, details, name='pages-details-by-slug'),
url(r'^$', details, {'slug': ''}, name='pages-root'),
])
我有一个 RoutingUrl 模型,它描述了我站点上使用的所有 urls 以及必须管理 url 和一些其他路由信息的视图(视图模型的外键) . url 的大小在不断增加,应该也支持重定向。型号大致如下:
class RoutingUrl(models.Model):
url = models.CharField(unique=True, verbose_name='routing url')
crc_checksum = models.IntegerField(editable=False)
redirect_to = models.ForeignKey('RoutingUrl', related_name='redirect_from', blank=True, null=True)
view = models.ForeignKey(View, related_name='routing_urls')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class View(models.Model):
name = models.CharField()
RoutingUrl 也有一个通用外键,模型包含有关要呈现的页面的信息(必须支持不同的模型,这就是通用外键的原因)。
现在的问题是:如何在django中实现这样的动态路由?我的感觉是我有两个选择:
- 我可以创建一个中间件,它将通过实施 process_request 方法(在检查 url 模式之前)负责将请求分派到正确的视图。显然这样的中间件应该位于中间件堆栈的底部,以保持其他中间件的功能。因此,该解决方案将绕过 Django 路由系统。
- 另一种选择是添加一个 catch all url 匹配所有内容的模式,然后只编写我自己的 handler/dispatcher 作为视图。该处理程序实现路由过程,因此将调用适当的视图和 return 它的 HttpResponse
你能建议我这两个选项中哪一个最适合实现这样的路由吗?当然,如果有第三种更好的选择,请不要犹豫向我推荐。
稍微调查一下 django 中间件挂钩,很明显 process_request 不是实现路由功能的最佳选择。事实上,从文档中:
It should return either None or an HttpResponse object. If it returns None, Django will continue processing this request, executing any other process_request() middleware, then, process_view() middleware, and finally, the appropriate view. If it returns an HttpResponse object, Django won’t bother calling any other request, view or exception middleware, or the appropriate view; it’ll apply response middleware to that HttpResponse, and return the result.
所以 HttpResponse 会破坏中间件堆栈功能。 process_view 大致相同,这将避免异常中间件的调用。此时采用第二种方案似乎更明智...
django-cms 插件证实了这种直觉,正如您可以从 urlpatterns 定义的 source code 中看到的那样:
from django.conf import settings
from django.conf.urls import url
from cms.apphook_pool import apphook_pool
from cms.appresolver import get_app_patterns
from cms.views import details
# This is a constant, really, but must live here due to import order
SLUG_REGEXP = '[0-9A-Za-z-_.//]+'
if settings.APPEND_SLASH:
regexp = r'^(?P<slug>%s)/$' % SLUG_REGEXP
else:
regexp = r'^(?P<slug>%s)$' % SLUG_REGEXP
if apphook_pool.get_apphooks():
# If there are some application urls, use special resolver,
# so we will have standard reverse support.
urlpatterns = get_app_patterns()
else:
urlpatterns = []
urlpatterns.extend([
url(regexp, details, name='pages-details-by-slug'),
url(r'^$', details, {'slug': ''}, name='pages-root'),
])