Flask中的动态导航

时间:2013-03-19 13:58:16

标签: python flask

我有一个非常简单的网站在Flask工作,所有这些都来自sqlite数据库。每个页面都作为一行存储在页面表中,其中包含路径,标题,内容等内容。

结构是分层的,页面可以有父级。因此,例如,'about'可能是一个页面,也可能有'about / something'和'about / cakes'。所以我想创建一个导航栏,其中包含指向父项为“/”(/是根页面)的所有链接的链接。此外,我还希望它还显示该页面的所有页面。

例如,如果我们在'about / cakes / muffins',除了总是显示的链接外,我们还会看到“about / cakes”的链接,以某种方式如此:

- About/
  - Cakes/
    - Muffins
    - Genoise
  - Pies/
- Stuff/
- Contact
- Legal
- Etc.[/]

带有子项的带有斜杠的斜杠,而不带有子项的页面带有斜杠。

代码:

@app.route('/')
def index():
    page = query_db('select * from page where path = "/"', one=True)
    return render_template('page.html', page=page, bread=[''])

@app.route('/<path>')
def page(path=None):
    page = query_db('select * from page where path = "%s"' % path, one=True)
    bread = Bread(path)
    return render_template('page.html', page=page, crumbs=bread.links)

我已经觉得我因为在那里有两个功能而违反DRY。但是进行导航会进一步违反它,因为我还希望在错误页面等内容上进行导航。

但我似乎找不到特别的Flasky方法来做到这一点。有什么想法吗?

2 个答案:

答案 0 :(得分:6)

“flasky”和pythonic方式将使用基于类的视图和模板层次结构

首先阅读两者的文档,然后根据这种方法重构代码:

class MainPage(MethodView):
    navigation=False
    context={}

    def prepare(self,*args,**kwargs):
        if self.navigation:
            self.context['navigation']={
                #building navigation
                #in your case based on request.args.get('page')
            }
        else:
            self.context['navigation']=None

    def dispatch_request(self, *args, **kwargs):
        self.context=dict() #should nullify context on request, since Views classes objects are shared between requests
        self.prepare(self,*args,**kwargs)
        return super(MainPage,self).dispatch_request(*args,**kwargs)

class PageWithNavigation(MainPage):
    navigation = True

class ContentPage(PageWithNavigation):
    def get(self):
        page={} #here you do your magic to get page data
        self.context['page']=page
        #self.context['bread']=bread
        #self.context['something_Else']=something_Else
        return render_template('page.html',**self.context)

然后你可以做以下事情: 为main_page.html和page_with_navigation.html创建单独的页面 然后你的每一页“error.html,page.html,somethingelse.html”基于其中一个。 关键是要动态地做到这一点:

稍微修改一下prepare方法:

def prepare(self):
        if self.navigation:
            self.context['navigation']={
                #building navigation
                #in your case based on request.args.get('page')
            }
        else:
            self.context['navigation']=None
        #added another if to point on changes, but you can combine with previous one
        if self.navigation:
            self.context['extends_with']="templates/page_with_navigation.html"
        else:
            self.context['extends_with']="templates/main_page.html"

你的模板: 的 main_page.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    {% block navigation %}
    {% endblock %}
    {% block main_content %}
    {% endblock %}
</body>
</html>

<强> page_with_navigation.html

{% extends "/templates/main_page.html" %}

{% block navigation %}
        here you build your navigation based on navigation context variable, which already passed in here
{% endblock %}

page.html或任何其他some_page.html。保持简单!
注意第一线。您的视图设置了哪个页面应该放在那里,您可以通过设置navigation = of view-class轻松调整它。

{% extends extends_with %}

{% block main_content %}
        So this is your end-game page.
        Yo do not worry here about navigation, all this things must be set in view class and template should not worry about them
        But in case you need them they still available in navigation context variable
{% endblock %}

答案 1 :(得分:2)

只需拥有多个装饰器即可在一个函数中完成:)

@app.route('/', defaults={'path': '/'})
@app.route('/<path>')
def page(path):
    page = query_db('select * from page where path = "%s"' % path, one=True)
    if path == '/':
        bread = Bread(path)
        crumbs = bread.links
    else:
        bread = ['']
        crumbs = None
    return render_template('page.html', page=page, bread=bread, crumbs=crumbs)

我个人会修改面包函数,但也适用于路径/

如果仅仅是为您的上下文添加变量,那么我建议您查看上下文处理器:http://flask.pocoo.org/docs/templating/#context-processors