flask实战-我的博客-模板 --

模板

personalBlog采用典型的博客布局,左侧三分之二为主体,显示文章列表、正文;右侧三分之一为边栏,显示分为类列表、社交连接等。如今的工做是将HTML文件加工为模板,并建立对应的表单类,在模板中渲染。javascript

并不是全部的页面都须要添加边栏,因此咱们不能把它放到基模板中。为了不重复和易于维护,咱们把边栏部分的代码放到了局部模板_sidebar.html中。除了基模板base.html和存储宏的macros.html模板,personalBlog程序的博客前台使用的模板以下所示:css

index.html 主页;html

about.html 关于页面;java

_sidebar.html 边栏;jquery

category.html 分类页面;shell

post.html 文章页面;bootstrap

login.html 登陆页面;缓存

400.html;cookie

404.html;app

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),清楚缓存并从新加载页面便可看到新的样式。

 

基模板中的一些代码咱们会在下面详细介绍,其余模板的实现咱们则会在实现具体的功能时介绍。

 

一、模板上下文

在基模板的导航栏以及博客主页中须要使用博客的标题、副标题等存储在管理员对象上的数据,为了不在每一个视图函数中渲染模板时传入这些数据,咱们在模板上下文函数中像模板上下文添加了管理员对象变量(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 %}

 

二、渲染导航连接

导航栏上的按钮应该再对应的页面显示激活状态。举例来讲,当用户单击导航栏上的“关于”按钮打开关于页面时,“关于”按钮应该高亮显示。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路径导入,它支持的经常使用参数以下所示:

 

三、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')
相关文章
相关标签/搜索