11章 博客文章

Posted cc-world

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了11章 博客文章相关的知识,希望对你有一定的参考价值。

1、模型

创建博客文章模型,与User建立外键关联

# 文章模型
class Post(db.Model):
    __tablename__ = posts
    id = db.Column(db.INTEGER, primary_key=True)
    body = db.Column(db.TEXT)
    timestamp = db.Column(db.DATETIME, index=True, default=datetime.utcnow)
    author_id = db.Column(db.INTEGER, db.ForeignKey(users.id))#外键关联
    body_html = db.Column(db.TEXT)#转换后的body字段,HTML格式,在模板中可以直接调用

    def __repr__(self):
        return self.body

# 用户模型
class User(UserMixin, db.Model):
    # 给User添加一个posts属性,给Post添加一个author属性, dynamic禁止自动执行查询
    posts = db.relationship(Post, backref=author, lazy=dynamic)

2、路由

在首页添加显示post的路由

@main.route(/, methods=[GET, POST])
def index():
    form = PostForm()
    if current_user.can(Permission.WRITE_ARTICLES) and form.validate_on_submit():
        post = Post(body=form.body.data,
                    author=current_user._get_current_object())#current_user由flask-login提供,和所有上下文一样,通过线程内的代理对象实现
        db.session.add(post)
        db.session.commit()
        return redirect(url_for(.index))
    # posts = Post.query.order_by(Post.timestamp.desc()).all()
    # 添加分页导航
    page = request.args.get(page, 1, type=int)#请求渲染的页数从request.args中获取,默认1
    #为了显示某页中的数据,要把all()转换成flask_SQLALchemy提供的paginate()方法
    #第一个参数page是必须的,per_page默认20,error_out:页数超过范围是返回一个空列表
    #paginate()方法的返回值是一个Paginate类对象,这个类在flask_SQLALchemy中定义,用于在模板中生成分页链接
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(
        page, per_page=current_app.config[FLASK_POSTS_PER_PAGE],error_out=False
    )
    posts = pagination.items
    return render_template(index.html, form=form, posts=posts, pagination=pagination)

 

3、视图 

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



{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello, {% if current_user.is_authenticated %}{{ current_user.username }}{% else %}Stranger{% endif %}!</h1>
</div>
<div>
    {% if current_user.can(Permission.WRITE_ARTICLES) %}
    {{ wtf.quick_form(form) }}
    {% endif %}
</div>
{% include ‘_posts.html‘ %}
{% if pagination %}
    <div class="pagination">
        {{ macros.pagination_widget(pagination, ‘.index‘) }}
    </div>
{% endif %}
{% endblock %}

 

 4、分页导航

 paginate()方法的返回值是一个Paginate类对象,这个类在flask_SQLALchemy中定义,用于在模板中生成分页链接。

Paginate类对象属性:

  items:当前页面中的记录

  query:分页的源查询

  page:当前页数

  prev_num:上一页的页数

  next_num

  has_next:入伙有下一页,返回True

  has_prev

  pages:总页数

  per_page:每页显示的记录数量

  total:查询返回的记录数量

 Paginate类对象方法:

   iter_pages():一个迭代器,返回一个在分页导航中显示的页数列表

  prev():上一页的分页对象

  next()

以jinja2宏的形式实现分页导航:

{% macro pagination_widget(pagination, endpoint) %}
<ul class="pagination">
    <li {% if not pagination.has_prev %} class="disabled" {% endif %}>
        <a href="
        {% if pagination.has_prev %}
            {{ url_for(endpoint,page=pagination.page-1, **kwargs) }}
        {% 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) }}">{{ p }}</a>
                </li>
            {% else %}
                <li>
                    <a href="{{ url_for(endpoint, page=p, **kwargs) }}">{{ p }}</a>
                </li>
            {% endif %}
        {% else %}
            <li class="disabled"><a href="#">&hellip;</a> </li>
        {% endif %}
    {% endfor %}
    <li {% if not pagination.has_next %} class="disabled" {% endif %}>
        <a href="
        {% if pagination.has_next %}{{ url_for(endpoint, page=pagination.page+1, **kwargs) }}
        {% else %}
            #
        {% endif %}">&raquo;</a>
    </li>
</ul>
{% endmacro %}

 

  5、使用Markdown和Flask-PageDown支持富文本文章

Flask-PageDown扩展定义了一个PageDownField类,这个类和WTForms中的TextAreaField接口一致

(1)初始化

from flask_pagedown import PageDown

pagedown = PageDown()
pagedown.init_app(app)

 

(2)修改表单

class PostForm(FlaskForm):
    # body = TextAreaField(‘what is your mind?‘, validators=[DataRequired()])
    body = PageDownField(what is your mind?, validators=[DataRequired()])#启用MarkDown的文章表单
    submit = SubmitField(Submit)

 

(3)Markdown预览 

Markdown预览使用PageDown库生成,Flask-PageDown简化了这个过程,提供了一个模板宏,从CDN中加载所需文件

{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{#Markdown文章预览使用PageDown库生成,下面的宏是从CDN中加载,要联网#}
{{ pagedown.include_pagedown() }}
{% endblock %}

 

 

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Sanitizer.min.js"></script>

 

 6、在服务器上处理富文本

# 文章模型
class Post(db.Model):
    __tablename__ = posts
    id = db.Column(db.INTEGER, primary_key=True)
    body = db.Column(db.TEXT)
    timestamp = db.Column(db.DATETIME, index=True, default=datetime.utcnow)
    author_id = db.Column(db.INTEGER, db.ForeignKey(users.id))#外键关联
    body_html = db.Column(db.TEXT)#转换后的body字段,HTML格式,在模板中可以直接调用

    def __repr__(self):
        return self.body


    @staticmethod
    #on_changed_body()注册在body字段上,是SQLALchemy ‘set‘ 事件的监听程序,只要body字段设了新值,就会自动调用该函数
    #该函数把body字段中的文本渲染成html格式,并保存在body_html中,完成markdown文本到html的转换
    def on_changed_body(target, value, oldvalue, initiator):
        allowed_tags = [a, abbr, b, blockquote, code, em, i, li,
                        ul, ol, pre, strong, h1, h2, h3, p, acronym]
        # 1markdown()把markdown文本转换成html
        # 2bleach.clean()删除不在allowed_tags中的标签
        # 3bleach.linkify()把纯文本的url转换成<a></a>链接,因为markdown官方没有为自动生成链接提供支持
        target.body_html = bleach.linkify(bleach.clean(
            markdown(value, output_format=html),
            tags=allowed_tags, strip=True
        ))

 

以上是关于11章 博客文章的主要内容,如果未能解决你的问题,请参考以下文章

ruby 我的博客文章“Rails中更好的条件验证”的片段

真题整理,10年真题逐章整理系列

第二模第11章 函数的基本使用

为 Blogger 上的博客格式化代码片段 [关闭]

错误记录Android Studio 编译报错 ( Could not determine java version from ‘11.0.8‘. | Android Studio 降级 )(代码片段

错误记录Android Studio 编译报错 ( Could not determine java version from ‘11.0.8‘. | Android Studio 降级 )(代码片段