flask實戰-個人博客-模板 --


模板

personalBlog采用典型的博客布局,左側三分之二為主體,顯示文章列表、正文;右側三分之一為邊欄,顯示分為類列表、社交鏈接等。現在的工作是將HTML文件加工為模板,並創建對應的表單類,在模板中渲染。

並非所有的頁面都需要添加邊欄,所以我們不能把它放到基模板中。為了避免重復和易於維護,我們把邊欄部分的代碼放到了局部模板_sidebar.html中。除了基模板base.html和存儲宏的macros.html模板,personalBlog程序的博客前台使用的模板如下所示:

index.html 主頁;

about.html 關於頁面;

_sidebar.html 邊欄;

category.html 分類頁面;

post.html 文章頁面;

login.html 登錄頁面;

400.html;

404.html;

500.html;

 

personalBlog中將會用到400錯誤響應,表示無效請求,所以我們添加了對應的錯誤頁面模板,在前面介紹工廠函數時我們已經編寫了對應的錯誤處理函數。

 

博客后台使用的模板如下所示:

manager_category.html 分類管理頁面;

new_category.html 新建分類頁面;

edit_category.html 編輯分類頁面;

manage_post.html 文章管理頁面;

new_post.html 新建文章頁面;

edit_post.html 編輯文章頁面;

settings.html 博客設置頁面;

manage_comment.html 評論管理頁面。

 

這些模板根據類別分別放到了templates目錄下的auth、admin、blog和errors子文件夾中,只有基模板在templates跟目錄內。基模板中定義了程序的基本樣式,包括導航欄和頁腳,如下所示。

 

personalblog/templates/base.html: 基模板

 

<!DOCTYPE html>
<html lang="en">
<head>
    {% block head %}
    <meta charset="utf-8">
    <meta name="viepoint" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>{% block title %}{% endblock title %} - PersonalBlog</title>
    <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/%s.min.css' % request.cookies.get('theme', 'perfect_blue')) }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css">
    {% endblock head %}
</head>
<body>
{% block nav %}
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
    <div class="container">
        <a class="navbar-brand" href="/">PersonalBlog</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01"
        aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarColor01">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                    <a class="nav-link" href="/">Home</a>a>
                </li>
            </ul>
        </div>
    </div>
</nav>
{% endblock nav %}
<main class="container">
    {% block content %}{% endblock content %}
    {% block footer %}
    <footer>
    </footer>
    {% endblock footer %}
</main>

{% block scripts %}
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-3.2.1.slim.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='jsj/bootstrap.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
{{ moment.include_moment(local_js=url_for('static', filename='js/moment-with-locales.min.js')) }}
{% endblock %}
</body>
</html>

 

除了基本的HTML結構,我們還在基模板中加載了Favicon、自定義CSS、JavaScript文件,以及Bootstrap、Moment.js所需的資源文件,並創建了一些塊用於在字模板中繼承。

 

Bootstrap默認的樣式足夠沒關,但也許你已經感到厭倦了。Bootswatch(https://bootswatch.com/)以及StartBootstrap(https://startbootstrap.com/)等網站上提供了許多免費的Bootstrap主題文件,你可以為自己的程序選擇一個。你需要下載對應的CSS文件,保存到static/css目錄下,替換Bootstrap的CSS文件(bootstrap.min.css),清楚緩存並重新加載頁面即可看到新的樣式。

 

基模板中的一些代碼我們會在下面詳細介紹,其他模板的實現我們則會在實現具體的功能時介紹。

 

1、模板上下文

在基模板的導航欄以及博客主頁中需要使用博客的標題、副標題等存儲在管理員對象上的數據,為了避免在每個視圖函數中渲染模板時傳入這些數據,我們在模板上下文函數中像模板上下文添加了管理員對象變量(admin)。另外,在多個頁面中都包含的邊欄中包含分類列表,我們也把分類數據傳入到模板上下文中,如下所示。

 

personalBlog/__init__.py: 處理模板上下文

 
def create_app(config_name = None):
    if config_name is None:
        config_name = os.getenv('FLASK_CONFIG', 'development')

    app = Flask('personalBlog')
    app.config.from_object(config[config_name])

    register_logging(app)  # 注冊日志處理器
    register_extensions(app)  # 注冊擴展(擴展初始化)
    register_blueprints(app)  # 注冊藍本
    register_commands(app)  # 注冊自定義shell命令
    register_errors(app)  # 注冊錯誤處理函數
    register_shell_context(app)  # 注冊錯誤處理函數
    register_template_context(app)  # 注冊模板上下文處理函數

    return app


def register_template_context(app):
    @app.context_processor
    def make_template_context():
        admin = Admin.query.first()
        categories = Category.query.order_by(Category.name).all()
        return dict(admin=admin, categories=categories)

 

獲取分類記錄時,我們使用order_by()對記錄進行排序,傳入的規則是分類模型的name字段,這會對分類按字母順序排列。在邊欄模板(_sidebar.html)中,我們迭代categories變量,渲染分類列表,如下所示:

personalBlog/templates/blog/_sidebar.html: 邊欄局部模板

 

{% if categories %}
<div class="card mb-3">
    <div class="card-header">Categories</div>
    <ul class="list-group list-group-flush">
        {% for category in categories %}
        <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
            <a href="{{ url_for('blog.show_category', category_id=category.id) }}">
                {{ category.name }}
            </a>
            <span class="badge badge-primary badge-pill">{{ category.posts|length }}</span>
        </li>
        {% endfor %}
    </ul>
</div>
{% endif %}

 

除了分類的名稱,我們還在每一個分類的右側顯示了與分類對應的文章總數,總數通過對分類對象的posts關系屬性添加length過濾器獲取。分類連接指向的blog.show_category視圖我們將在后面介紹。
 
在基模板(base.html)和主頁模板(index.html)中,我們可以直接使用傳入的admin對象獲取博客的標題和副標題。以主頁模板為例:
personalBlog/templates/blog/index.html:
 
{% extends 'base.html' %}
{% from 'bootstrap/ pagination.html' import render_pager %}

{% block title %}Home{% endblock %}

{% block content %}
    <div class="page-header">
        <h1 class="display-3">{{ admin.blog_title|default('Blog Title') }}</h1>
        <h4 class="text-muted">&nbsp;{{ admin.blog_sub_title|default('Blog Subtitle' }}</h4>
    </div>
    <div class="row">
        <div class="col-sm-8">
            {% include 'blog/_posts.html' %}
            {% if posts %}
                <div class="page-footer">{{ render_page(pagination }}</div>
            {% endif %}
        </div>
        <div class="col-sm-4 sidebar">
            {% include 'blog/_sidebar.html' %}
        </div>
    </div>
{% endblock %}

 

2、渲染導航鏈接

導航欄上的按鈕應該再對應的頁面顯示激活狀態。舉例來說,當用戶單擊導航欄上的“關於”按鈕打開關於頁面時,“關於”按鈕應該高亮顯示。Bootstrap為導航鏈接提供了一個active類來顯示激活狀態,我們需要為當前頁面對應的按鈕添加active類。

 

這個功能可以通過判斷請求的端點來實現,對request對象調用endpoint屬性即可獲得當前的請求端點。如果當前的端點與導航鏈接指向的端點相同,就為它添加active類,顯示激活樣式,如下所示:

<li {% if request.endpoint == 'blog.index' %}class="active"{% endif %}><a href="{{ url_for('blog.index') }}">Home</a>
</li>

 

有些教程中會使用endswith()方法來比較端點結尾。但是藍本擁有獨立的端點命名空間,即“<藍本命>.<端點名>”,不同的端點可能會擁有相同的結尾,比如blog.index和auth.index,這時使用endswith()會導致判斷錯誤,所以最妥善的做法是比較完整的端點值。

 

每個導航按鈕的代碼都基本相同,后面我們還會添加更多的導航鏈接。如果把這部分代碼放到宏里,然后正在需要的地方根據指定的參數調用,就可以讓模板更加整潔易讀了。下面是用於渲染導航鏈接的nav_link()宏:

{% macro nav_link(endpoint, text) -%}
    <li class="nav-item {% if request.endpoint
    and request.endpoint == endpoint %}active{% endif %}">
        <a class="nav-link" href="{{ url_for(endpoint, **kwargs) }}">{{ text }}</a>
    </li>
{%- endmacro %}

 

nav_link()宏接收完整的端點值和按鈕文本作為參數,返回完整的導航鏈接。因為錯誤頁面沒有端點值,當渲染錯誤頁面的導航欄時,鏈接會出現request.endpoint為None的錯誤。為了避免這個錯誤,需要在nav_link()宏的if判斷中額外添加一個判斷條件,確保端點不為None。

借助nav_link宏,渲染導航鏈接的代碼會變得非常簡單:

{% from 'macros.html' import nav_link %}
...
<ul class="navbar-nav mr-auto">
    {{ nav_link('index', 'Home') }}
    {{ nav_link('about', 'About') }}
</ul>
...

 

不過在personalBlog的模板中我們並沒有使用這個nav_link()宏,因為Bootstrap-Flask提供了一個更加完善的render_nav_item()宏,它的用法和我們創建的nav_link()宏基本相同。這個宏可以在模板中通過bootstrap/nav.html路徑導入,它支持的常用參數如下所示:

 

3、Flash消息分類

我們目前的Flash消息應用了Bootstrap的alert-info樣式,單一的樣式使消息的類別和等級難以區分,更合適的做法是為不同類別的消息應用不同的樣式。比如,當用戶訪問出錯時顯示一個黃色的警告消息;而不同的提示消息則使用藍色的默認樣式。bootstrap為提醒消息(Alert)提供了8種基本的樣式類,即alert-primary、alert-secondary、alert-success、alert-danger、alert-warning、alert-light、alert-dark,如下所示:

 

要開啟消息分類,我們首先要在消息渲染函數get_flashed_messages()中將with_categories參數設為True。這時會把消息迭代為一個類似於“(分類,消息)”的元祖,我們使用消息分類字符來構建樣式類,如下所示:

personalBlog/templates/base.html: 渲染分類消息

 

<main class="container"> {% for message in get_flashed_messages(with_categories=True) %} <div class="alert alert-{{ message[0] }}" role="alert">
        <button type="button" class="close" data-dismiss="alert">&times;</button> {{ message[1] }} </div> {% endfor %}

    {% block content %}{% endblock content %}
    {% block footer %}
    <footer>
    </footer>
    {% endblock footer %}
</main>

 

樣式類通過“alert-{{ message[0] }}”形式構建,所以在調用flash()函數時,消息的類別作為第二個參數傳入(primary、secondary、success、danger、warning、light、dark中的一個)。比如,下面的消息使用success分類,在渲染時會使用alert-success樣式類:

flash(u'發表成功!', 'success')

 

如果你不想使用Bootstrap,或是想添加一個自定義分類,可以通過在css文件中添加新的消息樣式的css類實現。比如下面的CSS類實現了一個自定義消息樣式類alert-matrix:

 

.alert-matrix{
    color: #66ff66;
    background-color: #000000;
    border-color: #ebccd1;
}

 

在調用flash()函數時,則使用“matrix”作為分類:

flash(u'發表成功!', 'matrix')

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM