如何将 HTML 标签+数据保存到sqlalchemy中?
How to save HTML tags + data into sqlalchemy?
我正在使用 Flask 和 sqlalchemy 创建个人博客网站。
在发布我的博客时,我希望发布的博客格式正确 html.
这是我的博客模型:
class Blog(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(), index=True)
description = db.Column(db.Text(), index=True)
content = db.Column(db.Text(), index=True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
likes = db.Column(db.Integer, default=0)
dislikes = db.Column(db.Integer, default=0)
comments = db.relationship('Comment', backref='commented_by', lazy='dynamic')
def __repr__(self):
return 'Title <>'.format(self.title)
这是我添加博客的表格:
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h1 class="code-line text-center" data-line-start="14" data-line-end="15">Add Blog</h1>
<br>
</div>
</div>
<form action="" method="POST" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.title.label }}<br>
{{ form.title(size=30) }}<br>
</p>
<p>
{{ form.description.label }}<br>
{{ form.description(size=30) }}<br>
</p>
<p>
{{ form.content.label }}<br>
{{ form.content() }}<br>
</p>
<p>
{{ form.submit() }}
</p>
</form>
{{ ckeditor.load() }}
{{ ckeditor.config(name='content') }}
{% endblock %}
这就是我呈现博客的方式:
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h1 class="code-line text-center" data-line-start="14" data-line-end="15">{{ blog.title }}</h1>
<br>
{{ blog.content }}
</div>
</div>
</div>
{% endblock %}
添加博客时,我使用的是文本编辑器
但是一旦它被发布并且我在查看博客页面上呈现它,没有 html 内容被呈现甚至没有换行符
如何在我的 sql 数据库中保存 html 内容和标签,然后使用 jinja 模板呈现它?
首先,错在哪里:
您从表单中的文本字段获得的文本与呈现它的 HTML 不同,您得到的是文本。
如果你想在那个表单中生成 HTML,你应该在你的模板中集成一个富文本编辑器,比如 quilljs.com 或 tiny.cloud,它将有一个你可以使用的字段, 获取它生成的 HTML,它还允许您创建美观的博客文章。
如果你也不想要这个,要从那个表格中得到 html,直接在那个表格中写 HTML 会给你你想要的。
在 markdown 的上下文中,实际上可以将相同的格式应用于您的 database-saved 内容。您可以使用一些软件包来帮助您在数据库中使用 HTML。
首先,让我推荐 Whosebug QA 表格。请注意它是如何启用 markdown 编辑和对正在编写的文本的一个漂亮的小预览。要启用预览,您可以在虚拟环境中安装 flask-pagedown
包。
(venv)$ pip3 install flask-pagedown
在您的应用程序实例中初始化一个 pagedown
对象,比如在 __init__.py
文件或您正在使用的任何其他文件中。
# __init__.py
from flask import Flask
from flask_pagedown import PageDown
app = Flask(__name__)
pagedown = PageDown(app)
在 HTML 中的 head
标签内,添加此 CDN 调用,其文件不需要包含在您的应用程序中。
<!-- base.html -->
{% block head %}
{{ pagedown.html_head() }}
{% endblock %}
或者这样:
<head>
{{ pagedown.html_head() }}
</head>
如果您更喜欢使用自己的 JavaScript 源文件,您可以直接将 Converter 和 Sanitizer 文件直接包含在 HTML 页面中,而不是调用 pagedown.html_head()
:
<head>
<script type="text/javascript" src="https://mycdn/path/to/converter.min.js"></script>
<script type="text/javascript" src="https://mycdn/path/to/sanitizer.min.js"></script>
</head>
现在,只需更新您的表单即可使用 PageDownField
:
# forms.py
from flask_pagedown.fields import PageDownField
class Post(FlaskForm):
post = PageDownField('Comment', validators=[DataRequired()])
或者这样:
<form method="POST">
{{ form.pagedown(rows=10) }}
</form>
就是这样!您应该可以在表格下方看到 client-side post 预览。
在服务器中处理富文本
当发出 post 请求时,只有原始 markdown 将被发送到数据库,预览将被丢弃。将 HTML 内容发送到您的数据库存在安全风险。攻击者可以轻松构造 HTML 与 markdown 源不匹配的序列并提交它们,这就是为什么只提交 markdown 文本的原因。进入服务器后,可以使用 Python markdown-to-html 转换器将该文本转换回 HTML。您可以使用两个包。然后在您的虚拟环境中安装,如下所示:
(venv)$ pip3 install markdown bleach
bleach
用于清理要转换为允许一组标签的 HTML。
此时,下一个合乎逻辑的步骤是在数据库中缓存您的 content
字段内容。这是通过在您的数据库中专门为此缓存内容添加一个新字段来完成的,比如说 content_html
。最好保留 content
字段,以备不时之需。
# models.py
class Blog(db.Model):
content = db.Column(db.String(140))
content_html = db.Column(db.String(140))
@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.content_html = bleach.linkify(bleach.clean(
markdown(value, output_format='html'),
tags=allowed_tags, strip=True))
def __repr__(self):
return f'Title {self.title}'
db.event.listen(Blog.content, 'set', Blog.on_changed_body)
on_changed_body()
函数被注册为 SQLAlchemy 的 body 的“设置”事件的侦听器,这意味着只要 body 字段设置为新值,它就会自动调用。处理函数呈现内容的 HTML 版本并将其存储在 content_html
中,有效地使 Markdown 文本完全自动转换为 HTML。
实际转换分 3 步完成:
markdown()
函数初始转换为 HTML。结果被传递给 clean()
函数,其中包含已批准的 HTML 标签
clean()
函数删除所有不在白名单中的标签。
bleach 中的 linkify()
函数将任何以纯文本编写的 URL 转换为正确的 <a>
links。自动 link 生成并没有正式出现在 Markdown 规范中,但却是一个非常方便的功能。在客户端,PageDown
支持此功能作为可选扩展,因此 linkify()
与服务器上的该功能相匹配。
在您的模板中,您可以在要 post 内容的位置添加条件,例如:
{% for blog in blogs %}
{% if blog.content_html %}
{{ blog.content_html | safe }}
{% else %}
{{ blog.content }}
{% endif %}
{% endfor %}
呈现 HTML 主体时的 | safe
后缀告诉 Jinja2
不要转义 HTML 元素。 Jinja2
作为安全措施默认转义所有模板变量,但是 Markdown-generated HTML 是由服务器生成的,因此直接呈现为 HTML.[= 是安全的42=]
我正在使用 Flask 和 sqlalchemy 创建个人博客网站。 在发布我的博客时,我希望发布的博客格式正确 html.
这是我的博客模型:
class Blog(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(), index=True)
description = db.Column(db.Text(), index=True)
content = db.Column(db.Text(), index=True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
likes = db.Column(db.Integer, default=0)
dislikes = db.Column(db.Integer, default=0)
comments = db.relationship('Comment', backref='commented_by', lazy='dynamic')
def __repr__(self):
return 'Title <>'.format(self.title)
这是我添加博客的表格:
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h1 class="code-line text-center" data-line-start="14" data-line-end="15">Add Blog</h1>
<br>
</div>
</div>
<form action="" method="POST" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.title.label }}<br>
{{ form.title(size=30) }}<br>
</p>
<p>
{{ form.description.label }}<br>
{{ form.description(size=30) }}<br>
</p>
<p>
{{ form.content.label }}<br>
{{ form.content() }}<br>
</p>
<p>
{{ form.submit() }}
</p>
</form>
{{ ckeditor.load() }}
{{ ckeditor.config(name='content') }}
{% endblock %}
这就是我呈现博客的方式:
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h1 class="code-line text-center" data-line-start="14" data-line-end="15">{{ blog.title }}</h1>
<br>
{{ blog.content }}
</div>
</div>
</div>
{% endblock %}
添加博客时,我使用的是文本编辑器
但是一旦它被发布并且我在查看博客页面上呈现它,没有 html 内容被呈现甚至没有换行符
如何在我的 sql 数据库中保存 html 内容和标签,然后使用 jinja 模板呈现它?
首先,错在哪里:
您从表单中的文本字段获得的文本与呈现它的 HTML 不同,您得到的是文本。
如果你想在那个表单中生成 HTML,你应该在你的模板中集成一个富文本编辑器,比如 quilljs.com 或 tiny.cloud,它将有一个你可以使用的字段, 获取它生成的 HTML,它还允许您创建美观的博客文章。
如果你也不想要这个,要从那个表格中得到 html,直接在那个表格中写 HTML 会给你你想要的。
在 markdown 的上下文中,实际上可以将相同的格式应用于您的 database-saved 内容。您可以使用一些软件包来帮助您在数据库中使用 HTML。
首先,让我推荐 Whosebug QA 表格。请注意它是如何启用 markdown 编辑和对正在编写的文本的一个漂亮的小预览。要启用预览,您可以在虚拟环境中安装 flask-pagedown
包。
(venv)$ pip3 install flask-pagedown
在您的应用程序实例中初始化一个 pagedown
对象,比如在 __init__.py
文件或您正在使用的任何其他文件中。
# __init__.py
from flask import Flask
from flask_pagedown import PageDown
app = Flask(__name__)
pagedown = PageDown(app)
在 HTML 中的 head
标签内,添加此 CDN 调用,其文件不需要包含在您的应用程序中。
<!-- base.html -->
{% block head %}
{{ pagedown.html_head() }}
{% endblock %}
或者这样:
<head>
{{ pagedown.html_head() }}
</head>
如果您更喜欢使用自己的 JavaScript 源文件,您可以直接将 Converter 和 Sanitizer 文件直接包含在 HTML 页面中,而不是调用 pagedown.html_head()
:
<head>
<script type="text/javascript" src="https://mycdn/path/to/converter.min.js"></script>
<script type="text/javascript" src="https://mycdn/path/to/sanitizer.min.js"></script>
</head>
现在,只需更新您的表单即可使用 PageDownField
:
# forms.py
from flask_pagedown.fields import PageDownField
class Post(FlaskForm):
post = PageDownField('Comment', validators=[DataRequired()])
或者这样:
<form method="POST">
{{ form.pagedown(rows=10) }}
</form>
就是这样!您应该可以在表格下方看到 client-side post 预览。
在服务器中处理富文本
当发出 post 请求时,只有原始 markdown 将被发送到数据库,预览将被丢弃。将 HTML 内容发送到您的数据库存在安全风险。攻击者可以轻松构造 HTML 与 markdown 源不匹配的序列并提交它们,这就是为什么只提交 markdown 文本的原因。进入服务器后,可以使用 Python markdown-to-html 转换器将该文本转换回 HTML。您可以使用两个包。然后在您的虚拟环境中安装,如下所示:
(venv)$ pip3 install markdown bleach
bleach
用于清理要转换为允许一组标签的 HTML。
此时,下一个合乎逻辑的步骤是在数据库中缓存您的 content
字段内容。这是通过在您的数据库中专门为此缓存内容添加一个新字段来完成的,比如说 content_html
。最好保留 content
字段,以备不时之需。
# models.py
class Blog(db.Model):
content = db.Column(db.String(140))
content_html = db.Column(db.String(140))
@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.content_html = bleach.linkify(bleach.clean(
markdown(value, output_format='html'),
tags=allowed_tags, strip=True))
def __repr__(self):
return f'Title {self.title}'
db.event.listen(Blog.content, 'set', Blog.on_changed_body)
on_changed_body()
函数被注册为 SQLAlchemy 的 body 的“设置”事件的侦听器,这意味着只要 body 字段设置为新值,它就会自动调用。处理函数呈现内容的 HTML 版本并将其存储在 content_html
中,有效地使 Markdown 文本完全自动转换为 HTML。
实际转换分 3 步完成:
markdown()
函数初始转换为 HTML。结果被传递给clean()
函数,其中包含已批准的 HTML 标签clean()
函数删除所有不在白名单中的标签。
bleach 中的 linkify()
函数将任何以纯文本编写的 URL 转换为正确的<a>
links。自动 link 生成并没有正式出现在 Markdown 规范中,但却是一个非常方便的功能。在客户端,PageDown
支持此功能作为可选扩展,因此linkify()
与服务器上的该功能相匹配。
在您的模板中,您可以在要 post 内容的位置添加条件,例如:
{% for blog in blogs %}
{% if blog.content_html %}
{{ blog.content_html | safe }}
{% else %}
{{ blog.content }}
{% endif %}
{% endfor %}
呈现 HTML 主体时的 | safe
后缀告诉 Jinja2
不要转义 HTML 元素。 Jinja2
作为安全措施默认转义所有模板变量,但是 Markdown-generated HTML 是由服务器生成的,因此直接呈现为 HTML.[= 是安全的42=]