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 %}
在资料页中显示博客文章
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 %}">
«
</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="#">…</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 %}">
»
</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-博客文章的更多相关文章
- Flask 学习 十 博客文章
提交和显示博客文章 app/models.py 文章模型 class Post(db.Model): __tablename__ = 'posts' id = db.Column(db.Integer ...
- 用 Flask 来写个轻博客 (22) — 实现博客文章的添加和编辑页面
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 新建表单 新建视图函数 新建模板 在博客文章页面添加 New 和 Ed ...
- Flask博客开发——Tinymce编辑器
之前Flask博客的文本编辑器比较简陋,这里为博客添加个优雅易用的Tinymce文本编辑器. 1.项目中添加Tinymce 下载好Tinymce包以及语言包,并添加到项目中.添加到项目的方法,参考了这 ...
- Flask博客开发——自定义头像
Flask Web开发一书中,使用了与个人邮箱绑定的Gravatar图形作为用户头像.Gravatar提供的头像比较简陋,而且可能由于网络问题无法生成头像.多数社交网站和博客提供用户自定义头像功能,因 ...
- SQL Sever 博客文章目录(2016-07-06更新)
SQL Server方面的博客文章也陆陆续续的写了不少了,顺便也将这些知识点整理.归纳一下下.方便自己和他人查看. MS SQL 数据类型 三大数据库对比研究系列--数据类型 MS SQL 表和视图 ...
- 使用 Microsoft Word 发布博客文章
以 Microsoft Word 2010 为例: 依次选择:文件 -> 保存并发送 -> 发布为博客文章 配置说明:新建账户 的 博客文章 URL 一栏填写 http://rpc.cn ...
- 年度十佳 DevOps 博客文章(后篇)
如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.在上篇文章中我们了解到 15 年十佳 DevOps 博客文章的第 6-10 名,有没有哪一篇抓住了您的眼球,让您 ...
- 年度十佳 DevOps 博客文章(前篇)
如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.国内 ITOM 领军企业 OneAPM 工程师为您翻译整理了,2015 年十佳 DevOps 文章,究竟是不是深 ...
- Word 2010发布博客文章
只测试了cnblog 1.新建文件选择word 2010自带的博客文章模板 2.在管理账户中新建一个博客账户,也就是你自己在博客园的账户,博客选其他 3.然后选择下一步,博客的URL在自己的博客设置里 ...
- VM 映像 PowerShell 教学系列博客文章
编辑人员注释:本文章是与Microsoft Azure工程的项目经理Kay Singh共同撰写的 正如我在第一篇博客文章中所承诺的,我又回来了,为大家分步介绍如何在PowerShell中使用VM ...
随机推荐
- nginx的基本操作
启动 nginx -c /etc/nginx/nginx.conf停止nginx -s stop nginx -s quit pkill -9 nginx重载nginx -s reload文件检测ng ...
- noip搜索模拟题 骰子
骰子 dice.cpp/c/pas 1s/128M [题目描述] 桌面上有两个特别的骰子.骰子的每一个面,都写了一个不同的数字.设第一个骰子上下左右前后分别为a1, a2, a3, a4, a5, a ...
- Linux环境 Java内存快速查看
最近生产环境遇到内存老是占用很大的情况,16G的内存Free的内存只剩100多M,仿佛一颗定时炸弹一般,说不定就服务Down了.于是开始网上不断的找查看内存使用的方法.现学现卖,以下通过一个例子来演示 ...
- ubuntu 14.04 安装minidwep-gtk
一,安装相关的依赖 sudo apt-get install build-essential libssl-dev iw libpcap-dev sqlite3 libsqlite3-dev libp ...
- Windows基础环境_安装配置教程(Windows7 64、JDK1.8、Android SDK23.0、TortoiseSVN 1.9.5)
Windows基础环境_安装配置教程(Windows7 64.JDK1.8.Android SDK23.0.TortoiseSVN 1.9.5) 安装包版本 1) JDK版本包 地址: htt ...
- .NET easyUI tree树状结构
简单的制作后台制作写一个json(string类型)格式 public partial class goodstype_type : System.Web.UI.Page { public strin ...
- 洛谷 P3387 【模板】缩点
题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ...
- 会写网页 就会写手机APP #2-- 范例修正 , Hybrid Mobile Apps for ASP.NET Developers (Apache Cordova)
原文出处:会写网页 就会写手机APP #2-- 范例修正 , Hybrid Mobile Apps for ASP.NET Developers (Apache Cordova) 这是我的文章备份 ...
- 使用工具Source Monitor测量您Java代码的环复杂度
代码的环复杂度(Cyclomatic complexity,有时也翻译成圈复杂度)是一种代码复杂度的衡量标准,在1976年由Thomas J. McCabe, Sr. 提出. 来看看计算公式. 代码环 ...
- IT界程序员几大恶习能立即让你变穷,你有吗?
IT软件开发,确实是各行业中薪水排名靠前的职业,月薪在八千以上的Java程序员多不胜数,但是不知有没有以下几种恶习?如果粘上一种,哪怕你薪水几万,估计最后也是囊中羞涩:综上所述列举以下几点,亲们自己对 ...