5

I have a pretty simple site working in Flask that's all powered from an sqlite db. Each page is stored as a row in the page table, which holds stuff like the path, title, content.

The structure is hierarchical where a page can have a parent. So while for example, 'about' may be a page, there could also be 'about/something' and 'about/cakes'. So I want to create a navigation bar with links to all links that have a parent of '/' (/ is the root page). In addition, I'd like it to also show the page that is open and all parents of that page.

So for example if we were at 'about/cakes/muffins', in addition to the links that always show, we'd also see the link to 'about/cakes', in some manner like so:

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

with trailing slashes for those pages with children, and without for those that don't.

Code:

@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)

I already feel like I'm violating DRY for having two functions there. But doing navigation will violate it further, since I also want the navigation on things like error pages.

But I can't seem to find a particularly Flasky way to do this. Any ideas?

4

2 回答 2

7

“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。把事情简单化!
注意第一行。您的视图设置应该进入哪个页面,您可以通过设置视图类的导航 = 轻松调整它。

{% 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 %}
于 2013-03-20T13:41:07.687 回答
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

于 2013-03-19T14:04:49.117 回答