我有一个有几百页的网站,其中可能 75% 的页面是静态内容,其余的符合典型的“Web 应用程序”模型。我的偏好是 Django,所以我一直在寻找基于它的解决方案。
内容是非常定制的——除了基本的站点 chrome 之外,大多数页面几乎没有共享,并且足够复杂,用 HTML 编写它们比尝试使用富文本编辑器提供正确的输出更简单。所以我目前的方向是只定义模板中的内容——我有一个单一的视图,并使用传入路径作为模板路径。这将站点上的每个页面保留为文件系统中的一个页面(易于浏览,易于在修订控制中跟踪),但允许每个页面共享任意数量的公共元素(页眉、页脚、导航)并将其自己的数据注入他们根据需要。
但是,这会陷入很多细节中。例如:
- 与其他页面共享页面数据。例如,一个页面定义的标题应该显示在其他页面的导航菜单中,等等。我发现了这个关于从模板中获取块值的问题,但这看起来真的很复杂(而且不可扩展)。
- 相关问题:如果我将某些东西定义为一个块,我只能使用它一次。我已经在 SO 中看到了 {% block title %} 的示例——它通常出现在页面的多个位置——但没有很好的解决方案。
- 多重/灵活的继承。对于面包屑,我可能想从页面的祖先继承,但对于布局,我可能想从其他东西继承(例如,一列与两列基本模板)。
我认为这些具体问题可以自行解决,主要是通过使用包含和自定义模板标签,但是向下看,我看到黑客堆积在黑客之上,我想避免这种情况——这需要相当简单和易于理解的系统。
在研究这些的过程中,我遇到了Hyde,它似乎解决了很多这些问题。特别是,我真的很喜欢它具有站点结构的感觉,并且它为页面提供了一些很好的导航工具。
但我仍然拥有所有动态的部分,它们确实需要无缝配合。因此,我为内容页面所做的任何事情都应该适用于作为动态应用程序一部分的任何模板。此外,我真正喜欢“每个页面一个模板”方法的一件事是,我可以通过将其路径添加到 urls.py 并指定自定义视图来更改任何特定页面的处理方式。
这种类型的用例有没有好的解决方案?更一般地说,这只是不应该要求 Django 做的事情吗?我突然想到,我在这里尝试将文件系统用作 CMS 数据库,这似乎可能会导致扩展问题,但 Django 似乎可以很好地处理和缓存模板内容,并且在查看了一些现有的 CMS 之后解决方案(django-cms、feincms、fiber) 我真的不喜欢有一个静态内容解决方案和一个完全不同的交互式内容解决方案的想法。
编辑
这是我使用自定义标签来处理页面元数据/配置的结果:
- 页面数据的字典在顶层传入(以便标签可以写入其中,然后堆栈中更高的代码可以将其读回)
- 自定义数据标签允许页面将数据写入此页面数据
- 其他自定义标签从数据中读取和呈现结构(导航、面包屑等)
主要部分是将数据(以 JSON 格式写入)读入全局字典的标签:
class PageInfoNode(Node):
def __init__(self, page_info):
self.title = page_info['title']
self.breadcrumb_title = page_info.get('breadcrumb_title', self.title)
self.show_breadcrumb = page_info.get('show_breadcrumb', False)
self.nav_title = page_info.get('nav_title', self.breadcrumb_title)
self.side_nav = page_info.get('side_nav', None)
def render(self, context):
# 'page_info' must be set someplace higher in the context stack
page_info = context['page_info']
page_info['title'] = self.title
page_info['nav_title'] = self.nav_title
if self.show_breadcrumb:
if 'breadcrumb' in page_info:
page_info['breadcrumb'] = [self.breadcrumb_title] + page_info['breadcrumb']
else:
page_info['breadcrumb'] = [self.breadcrumb_title]
if self.side_nav != None:
page_info['side_nav'] = self.side_nav
return ''
@register.tag
def pageinfo(parser, token):
nodelist = parser.parse(('endpageinfo',))
parser.delete_first_token()
return PageInfoNode(json.loads(nodelist.render(Context())))
每个页面将其数据设置为:
{% block data %}
{{ block.super }}
{% load my_page_tags %}
{% pageinfo %}
{
"title": "My Page Title",
"show_breadcrumb": true,
"side_nav": ["/section1/page.html", "/section2/page.html"]
}
{% endpageinfo %}
{% endblock data %}
这行得通,但它似乎真的不透明和脆弱:
- 需要以某种方式添加全局字典 - 现在我在视图中执行此操作,但我想自定义上下文处理器会更好
- 这需要在继承的块中,以便它实际呈现
- 因为我们有时需要超级数据(例如面包屑)它需要调用 {{ block.super }} 但它需要以正确的顺序来防止超级数据覆盖目标页面的数据。
我只是觉得我的工作方式与 Django 想要的操作方式背道而驰,我希望有更好的方法来处理我错过的这类事情。