Flask中的动态导航

Tom*_*ick 4 python flask

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

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

例如,如果我们在'about/cakes/muffins',除了总是显示的链接之外,我们还会看到"about/cakes"的链接,在某种程度上如此:

- About/
  - Cakes/
    - Muffins
    - Genoise
  - Pies/
- Stuff/
- Contact
- Legal
- Etc.[/]
Run Code Online (Sandbox Code Playgroud)

带有子项的带有斜杠的斜杠,而没有带有子项的页面则带有斜杠.

码:

@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)
Run Code Online (Sandbox Code Playgroud)

我已经觉得我因为在那里有两个功能而违反DRY.但是导航会进一步违反它,因为我还想在错误页面之类的东西上导航.

但我似乎无法找到一种特别的Flasky方法来做到这一点.有任何想法吗?

Tig*_*gra 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)
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行以下操作:为main_page.html和page_with_navigation.html创建单独的页面然后您的每个页面"error.html,page.html,somethingelse.html"基于其中一个.关键是要动态执行此操作:

稍微修改一下准备方法:

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"
Run Code Online (Sandbox Code Playgroud)

你的模板: main_page.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    {% block navigation %}
    {% endblock %}
    {% block main_content %}
    {% endblock %}
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

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 %}
Run Code Online (Sandbox Code Playgroud)

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 %}
Run Code Online (Sandbox Code Playgroud)