提交和显示博客文章

文章模型

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 %}

在资料页中显示博客文章

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

在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 %}

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

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 %}

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 %}

flask-博客文章的更多相关文章

  1. Flask 学习 十 博客文章

    提交和显示博客文章 app/models.py 文章模型 class Post(db.Model): __tablename__ = 'posts' id = db.Column(db.Integer ...

  2. 用 Flask 来写个轻博客 (22) — 实现博客文章的添加和编辑页面

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 新建表单 新建视图函数 新建模板 在博客文章页面添加 New 和 Ed ...

  3. Flask博客开发——Tinymce编辑器

    之前Flask博客的文本编辑器比较简陋,这里为博客添加个优雅易用的Tinymce文本编辑器. 1.项目中添加Tinymce 下载好Tinymce包以及语言包,并添加到项目中.添加到项目的方法,参考了这 ...

  4. Flask博客开发——自定义头像

    Flask Web开发一书中,使用了与个人邮箱绑定的Gravatar图形作为用户头像.Gravatar提供的头像比较简陋,而且可能由于网络问题无法生成头像.多数社交网站和博客提供用户自定义头像功能,因 ...

  5. SQL Sever 博客文章目录(2016-07-06更新)

    SQL Server方面的博客文章也陆陆续续的写了不少了,顺便也将这些知识点整理.归纳一下下.方便自己和他人查看. MS SQL 数据类型 三大数据库对比研究系列--数据类型 MS SQL 表和视图 ...

  6. 使用 Microsoft Word 发布博客文章

    以 Microsoft Word 2010 为例: 依次选择:文件 -> 保存并发送 -> 发布为博客文章 配置说明:新建账户 的 博客文章 URL  一栏填写 http://rpc.cn ...

  7. 年度十佳 DevOps 博客文章(后篇)

    如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.在上篇文章中我们了解到 15 年十佳 DevOps 博客文章的第 6-10 名,有没有哪一篇抓住了您的眼球,让您 ...

  8. 年度十佳 DevOps 博客文章(前篇)

    如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.国内 ITOM 领军企业 OneAPM 工程师为您翻译整理了,2015 年十佳 DevOps 文章,究竟是不是深 ...

  9. Word 2010发布博客文章

    只测试了cnblog 1.新建文件选择word 2010自带的博客文章模板 2.在管理账户中新建一个博客账户,也就是你自己在博客园的账户,博客选其他 3.然后选择下一步,博客的URL在自己的博客设置里 ...

  10. VM 映像 PowerShell 教学系列博客文章

     编辑人员注释:本文章是与Microsoft Azure工程的项目经理Kay Singh共同撰写的 正如我在第一篇博客文章中所承诺的,我又回来了,为大家分步介绍如何在PowerShell中使用VM ...

随机推荐

  1. Vue2之页面 、js 、css分离

    在编写vue的时候,页面数据少的时候,可以将所有的js和css都可以直接写在页面上,但是页面数据多,js.css的方法和样式多的时候,都放在一个页面的时候,就显得页面vue十分的臃肿. 所以写项目的时 ...

  2. 【翻译转载】【官方教程】Asp.Net MVC4入门指南(3):添加一个视图

    3. 添加一个视图 · 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-vi ...

  3. (译)Cg Programming/Unity(Cg编程/Unity)

    最近在学习Unity3d中的shader编程,能找到的中文资料比较少,于是,尝试翻译一下wiki Books上的资料,以方便其他跟我一样的入门学习者.由于是第一次翻译技术资料,经验不足,难免出错,请路 ...

  4. 中介者模式和php实现

    中介者模式: 中介者模式(Mediator Pattern)定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互.中介者模 ...

  5. GreenDao的简单使用说明(五)多表n:m

    在设计一些比较复杂的数据库结构的时候,我们会遇到表之间是n:m的关系,就是常说的多对多的关系,最常用的情况,就是用户权限这块,日常最常见的就是学生与老师的关系了,哪么我们来看一下GreenDao中如何 ...

  6. 初识SeekBar

    SeekBar拖动条,是Progress的间接子类 <SeekBar android:id="@+id/seekBar1" android:layout_width=&quo ...

  7. Spark Job调优(Part 1)

    原文链接:https://wongxingjun.github.io/2016/05/11/Spark-Job%E8%B0%83%E4%BC%98-Part-1/ Spark应用的执行效率是所有程序员 ...

  8. Contour Features 边界特征

    查找轮廓 findContours   cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) → image ...

  9. Python正则表达式计算器流程图

  10. C语言结构体和共用体_07

    概述 定义结构体类型变量的方法 结构体变量的引用 结构体变量的初始化 结构体数组 指向结构体类型数据的指针 用指针处理链表 共用体 枚举类型 用 typedef定义类型  概述 定义一个结构体的一般形 ...