Flask实战4-博客文章

本实战内容包括: 分页,markdown支持

分页

利用Flask-SQLAlchemy提供的paginate方法:

page页数是唯一需求的参数,error_out=True如果页数超出了范围则返回404

# ...
pagination = query.order_by(Post.timestamp.desc()).paginate(    # paginate是Flask-SQLAlchemy提供的分页方法
    page, per_page=current_app.config['FLASKR_POSTS_PER_PAGE'], error_out=False
)

paginate()方法的返回值是一个Pagination类对象,这个类在Flask-SQLAlchemy中定义。这个对象包含很多属性,用于在模版中生成分页链接,因此将其作为参数传入模版,分页对象属性简介:

属性 说明
items 当前页面中的记录
query 分页的源查询
page 当前页数
prev_num 上一页页数
next_num 下一页页数
has_next 如果有下一页,返回True
has_prev 如果有上一页,返回True
pages 总页数
per_page 每页显示的记录数
total 查询返回的记录总数
prev() 上一页分页对象
next() 下一页分页对象

配合Bootstrap的分页CSS,实现分页模版宏:

其中最关键的就是分页对象的iter_pages()方法

iter_pages()返回一个迭代器,返回一个在分页中显示页数的列表。这个这个列表最左边显示left_edge页,最右边显示right_edge页 当前页面左边显示left_current页,当前页面右边显示right_current页;例如,在一个100页的列表中。当前页面第50页,使用默认配置,该方法返回值如下:1, 2, None, 48, 49, 50, 51, 52, 53, 54, 55, None, 99, 100 (None表示页数之间的间隔)

iter_pages(left_edge=2, left_current=2, right_current=5, right_edge=2)
{% macro pagination_widget(pagination, endpoint, fragment='') %}
<ul class="pagination">
{#    没有前一页,添加class=disble,不可点击,a href=##}
    <li{% if not pagination.has_prev %} class="disabled"{% endif %}>
        <a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.prev_num, **kwargs) }}{{ fragment }}{% else %}#{% endif %}">
            &laquo;
        </a>
    </li>
    {% for p in pagination.iter_pages() %}
        {% if p %}
            {% if p == pagination.page %}
            <li class="active">
                <a href="{{ url_for(endpoint, page = p, **kwargs) }}{{ fragment }}">{{ p }}</a>
            </li>
            {% else %}
            <li>
                <a href="{{ url_for(endpoint, page = p, **kwargs) }}{{ fragment }}">{{ p }}</a>
            </li>
            {% endif %}
        {% else %}
        <li class="disabled"><a href="#">&hellip;</a></li>
        {% endif %}
    {% endfor %}
{#    没有后一页,添加class=disble,不可点击,a href=##}
    <li{% if not pagination.has_next %} class="disabled"{% endif %}>
        <a href="{% if pagination.has_next %}{{ url_for(endpoint, page=pagination.next_num, **kwargs) }}{{ fragment }}{% else %}#{% endif %}">
            &raquo;
        </a>
    </li>
</ul>
{% endmacro %}

在其他默认里使用分页宏

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% import "_macros.html" as macros %}

<div class="pagination">
    {{ macros.pagination_widget(pagination, '.index') }}
</div>

MarkDown

实现这个功能需要用到一些包:

  • PageDown: 使用JavaScript实现的客户端Markdown到HTML的转换
  • Flask-PageDown: 为Flask包转的PageDown, 把PageDown集成到Flask-WTF的表单中
  • MarkDown: 使用python实现服务器端markdown到html的转换
  • Bleach: 使用python实现的HTML清理器

使用Flask-PageDown

Flask-PageDown扩展定义了一个PageDownField类,这个类和WTForms中的TextAreaField接口一致。使用PageDownField之前。先要初始化扩展:

from flask_pagedown import PageDown

pagedown = PageDown()
pagedown.init_app(app)

将表单模型中的TextAreaField类型替换为PageDownFiled类型

from flask_pagedown.fields import PageDownField

class PostForm(Form):
    # body = TextAreaField("What's on your mind?", validators=[DataRequired()])
    body = PageDownField("What's on your mind?", validators=[DataRequired()])
    submit = SubmitField('Submit')

在模版中添加pagedown的js

{% block scripts %}
    {{ super() }}
    {{ pagedown.include_pagedown() }}
{% endblock %}

在服务器上处理markdown到html并存入DB

先使用python markdown将markdown转换成html,在使用bleach清理,确保只保存只允许的html标签,在数据模型中添加转换方法:

from markdown import markdown
import bleach


class Poset(db.Model):
    # ...
    body_html = db.Column(db.Text)
    
    @staticmethod
    def on_changed_body(target, value, oldvalue, initiator):
        allowed_tags = [
            'a', 'abbr', 'acronym', 'b', 'blockquote', 'code',
            'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul',
            'h1', 'h2', 'h3', 'p'
        ]
        target.body_html = bleach.linkify(bleach.clean(markdown(value, output_format='html'), tags=allowed_tags, strip=True))

# on_changed_body 函数注册在 body 字段上,是 SQLAlchemy“set”事件的监听程序,这意 味着只要这个类实例的 body 字段设了新值,函数就会自动被调用。

db.event.listen(Post.body, 'set', Post.on_changed_body)

在模版中显示

{% if post.body_html %}
    {{ post.body_html | safe }}  # 告诉jinja不转移html
{% else %}
    {{ post.body }}
{% endif %}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容

  • 第十一章 博客文章 本章将实现Flasky博客的核心功能,允许用户读取和撰写文章。你将学到一些关于模板重用、长项目...
    易木成华阅读 1,004评论 0 1
  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,176评论 22 257
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,082评论 4 62
  • 这几天老是下雨,天雾蒙蒙的,我坐在窗边远眺思绪就这样回到过去,回到以前雾蒙蒙的那个雨天。 那是十月,秋老虎...
    言大盗阅读 350评论 0 1
  • 我为什么来简书呢?首当其冲的原因是这里有一个让自己十分舒服的写作界面,它满足了我最基本的写作需要(虽然被吐槽过千百...
    千山阅读 1,925评论 22 27