5

私はFlaskで動作する非常にシンプルなサイトを持っています。これはすべてsqliteデータベースから供給されています。各ページは、パス、タイトル、コンテンツなどを保持するページテーブルに行として格納されます。

構造は階層的であり、ページは親を持つことができます。したがって、たとえば、「about」はページである可能性がありますが、「about/something」および「about/cakes」も存在する可能性があります。そこで、親が「/」(/はルートページ)を持つすべてのリンクへのリンクを含むナビゲーションバーを作成したいと思います。さらに、開いているページとそのページのすべての親も表示したいと思います。

したがって、たとえば、「about / keys / 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)

そこに2つの機能があることでDRYに違反しているような気がします。しかし、エラーページなどのナビゲーションも必要なので、ナビゲーションを行うとさらに違反します。

しかし、私はこれを行うための特にFlaskyな方法を見つけることができないようです。何か案は?

4

2 に答える 2

7

「薄っぺらな」そして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に別々のページを作成し、それらの1つに基づいてすべてのページ「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。単純にする!
最初の行に注意してください。ビューは、そこに配置するページを設定し、view-classのnavigation=を設定することで簡単に調整できます。

{% 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

複数のデコレータを使用するだけで、1つの関数でそれを実行できます:)

@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 に答える