zoukankan      html  css  js  c++  java
  • flask-博客文章

    提交和显示博客文章 

    文章模型

    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'))
    

    博客文章表单

    app/main/forms.py

    class PostForm(FlaskForm):
        body = TextAreaField(u'说说',validators=[Required()])
        submit = SubmitField(u'发表')
    

    处理博客文章的首页路由

    app/main/views.py

    @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())
            db.session.add(post)
            db.session.commit()
            return redirect(url_for('.index'))
        posts = Post.query.order_by(Post.timestamp.desc()).all()
        return render_template('index.html',form=form,posts=posts)
    

    显示博客文章的首页模板

    {% extends "base.html" %}
    {% import 'bootstrap/wtf.html'as wtf %}
    
    {% block title %}Flasky{% endblock %}
    
    {% block page_content %}
        <div class="page-header">
        <h1>欢迎 {% if current_user.is_authenticated %}{{ current_user.username }}{% else %}{% endif %}!</h1>
        </div>
        <div>
        {% if current_user.can(Permission.WRITE_ARTICLES) %}
        {{ wtf.quick_form(form) }}
        {% endif %}
        </div>
        <br/>
        <br/>
        <br/>
        <ul class="posts" style="list-style: none">
    {% for post in posts %}
        <li class="post">
            <div class="post-thumbnail">
                <a href="{{ url_for('.user',username=post.author.username) }}">
                   <img class="img-rounded profile-thumbnail" src="{{ post.author.gravatar(size=40) }}" style="float: left">
                </a>
            </div>
            <div class="post-date" style="float: right">{{ moment(post.timestamp).fromNow() }}</div>
            <div class="post-author">
                <a href="{{ url_for('.user',username=post.author.username) }}" style="padding-left: 20px">
                   {{ post.author.username }}
                </a>
            </div>
            <div class="post-body" style="padding-left: 60px;padding-bottom: 30px" >{{ post.body }}</div>
        </li>
        {% endfor %}
        </ul>
    {% endblock %}
    View Code

    在资料页中显示博客文章

    P118

    创建虚拟博客文章数据

    安装:pip install forgerypy

    生成虚拟用户和博客文章

    class User(UserMixin,db.Model):
        #...
    
        @staticmethod
        def generate_fake(count=100):
            from sqlalchemy.exc import IntegrityError
            from random import seed
            import forgery_py
    
            seed()
            for i in range(count):
                u = User(email=forgery_py.internet.email_address(),
                         username=forgery_py.internet.user_name(True),
                         password=forgery_py.lorem_ipsum.word(),
                         confirmed=True,
                         name=forgery_py.name.full_name(),
                         location=forgery_py.address.city(),
                         about_me=forgery_py.lorem_ipsum.sentence(),
                         member_since=forgery_py.date.date(True))
                db.session.add(u)
                try:
                    db.session.commit()
                except IntegrityError:
                    db.session.rollback()
    
    
    
    class Post(db.Model):
        @staticmethod
        def generate_fake(count=100):
            from random import seed, randint
            import forgery_py
    
            seed()
            user_count = User.query.count()
            for i in range(count):
                u = User.query.offset(randint(0, user_count - 1)).first()
                p = Post(body=forgery_py.lorem_ipsum.sentences(randint(1, 5)),
                         timestamp=forgery_py.date.date(True),
                         author=u)
                db.session.add(p)
                db.session.commit()
    View Code

    在puython  shell中生成

      >>>User.genetate_fake(100)

      >>>User.genetate_fake(100)

     在页面中渲染数据

    @main.route('/',methods=['GET','POST'])
    def index():
        #...
        
        
    
        page = request.args.get('page',1,type=int)
        pagination = Post.query.order_by(Post.timestamp.desc()).paginate(
            page,per_page=current_app.config['FLASKY_POSTS_PER_PAGE'],
            error_out=False
        )
        posts = pagination.items
        return render_template('index.html',form=form,posts=posts,pagination=pagination)
    

    添加分页导航

    分页导航宏

    app/templates/_macros.html

    {% macro pagination_widget(pagination, endpoint) %}
    <ul class="pagination  pagination-lg">
        <li{% if not pagination.has_prev %} class="disabled"{% endif %}>
            <a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.prev_num, **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.next_num, **kwargs) }}{% else %}#{% endif %}">
                &raquo;
            </a>
        </li>
    </ul>
    {% endmacro %}
    View Code

    在博客文章列表下面添加分页导航:

    app/templates/index.html:

    {% extends "base.html" %}
    {% import 'bootstrap/wtf.html'as wtf %}
    {% import "_macros.html" as macros %}
    
        #...
    
        {% include '_posts.html' %}   #文章
    
        {% if pagination %}
    <div class="pagination " style="float: right">
        {{ macros.pagination_widget(pagination , '.index') }}
    </div>
        {% endif %}

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

    如果用户想发布长文章,就会觉得在格式上受到了限制。那么就需要使用输入文章的多行文本输入框升级,让其支持Markdown语法,还要添加富文本文章的预览功能

      安装: pip install flask-pagedown markdown bleach

      使用Flask-PageDown

      初始化:

    from flask_pagedown import PageDown
    
    pagedown = PageDown()
    def create_app(config_name):
    
        pagedown.init_app(app)
    
    
        return app
    

    若想把首页的输入框改成Markdown富文本编辑器,PostForm表单中的body字段进行修改。

    from flask_pagedown.fields import PageDownField
    
    class PostForm(FlaskForm):
        body = PageDownField(u'发表文章',validators=[Required()])
        submit = SubmitField(u'确定')
    

    Flask-Pagedown模板声明

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

    在服务器上处理富文本

    提交表单后,POST请求只会发送纯Markdown文本,页面中显示的HTML预览会被丢掉。安全起见,只提交Markdown源文本,在服务器上使用Markdown将其转换成HTML。得到HTML后,再使用Bleach进行清理,确保其中只包含几个允许使用的HTML标签

    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)
        
        @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))

    markdown()函数初步把Markdown文本转换成HTML。然后把得到的结果和允许使用的HTML标签列表传给clean()函数。clean()函数删除所有不在白名单的标签。转换的最后一步由linkify()函数完成,这个函数由Bleach提供,把纯文本中的URL转换成适当的<a>标签。

    最后,如果post.body_html字段存在,还要把post.body换成post.body_html:

    app/templates/_posts.hrml:在模板中使用文章内容的HTML格式

    <div class="post-body" >
        {% if post.body_html %}
            {{ post.body_html | safe }}
        {% else %}
            {{ post.body }}
        {% endif %}
    </div>

    博客文章的固定链接

    app/main/views.py:文章的固定链接

    @main.route('/post/<int:id>')
    def post(id):
        post = Post.query.get_or_404(id)
        return render_template('post.html',posts=[post])
    

    post.html模板接受一个列表作为参数,这个列表就是要渲染的文章。这里必须要传入列表,因为只有这样,index.html和user。html引用的_posts.html模板才能在这个页面中使用。

    app/templates/_posts.html:文章的固定链接

            <a href="{{ url_for('.post',id=post.id) }}">
                <span class="label label-default">文章</span>
            </a>
    

    app/templates/post.html:固定链接模板

    {% extends 'base.html' %}
    {% block title %}Flask - Post{% endblock %}
    
    {% block page_content %}
    {% include '_posts.html' %}
    {% endblock %}
    

    博客文章编辑器

    aapp/main/views.py:编辑博客文章的路由,管理员可以编辑所有的文章

    @main.route('/edit/<int:id>',methods=['GET','POST'])
    @login_required
    def edit(id):
        post = Post.query.get_or_404(id)
        if current_user != post.author and 
            not current_user.can(Permission.ADMINISTER):
            abort(403)
        form = PostForm()
        if form.validate_on_submit():
            post.body =  form.body.data
            db.session.add(post)
            db.session.commit()
            flash('The post has been updated.')
            return redirect(url_for('.post',id=post.id))
        form.body.data = post.body
        return render_template('edit_post.html',form=form)
    

    app/templates/_posts.html:编辑博客文章的链接

            {% if current_user == post.author %}
            <a href="{{ url_for('.edit',id=post.id) }}">
                <span class="label label-primary">编辑</span>
        </a>
            {% elif current_user.is_administrator() %}
            <a href="{{ url_for('.edit',id=post.id) }}">
                <span class="label label-danger">编辑</span>
            </a>
            {% endif %}
    View Code

    app/templates/edit_post.html:编辑博客文章的模板.

    {% extends 'base.html' %}
    {% import 'bootstrap/wtf.html'as wtf %}
    
    {% block title %}Flask-edit{% endblock %}
    {% block page_content %}
    <div class="page-header">
        <h1>Edit Post</h1>
    </div>
    <div>
        {{ wtf.quick_form(form) }}
    </div>
    {% endblock %}
    
    {% block scripts %}
    {{ super() }}
    {{ pagedown.include_pagedown() }}
    {% endblock %}
    View Code
  • 相关阅读:
    8、【C++基础】内存管理
    7、【C++基础】内联函数、友元函数
    5、【C++基础】强制类型转换
    4、【C++基础】引用和指针
    3、【C++基础】基本的输入输出
    2、【C++基础】命名空间
    1、【C++基础】bool数据类型
    13、【C语言基础】预处理器、头文件
    6、git常用命令总结
    5、git标签管理
  • 原文地址:https://www.cnblogs.com/liushaocong/p/7429991.html
Copyright © 2011-2022 走看看