源代码: https://github.com/ltoddy/flask-tutorial
技术交流群:630398887(欢迎一起吹牛)
写在前面的话:如果你实在不会写页面,复制粘贴你会吧.
https://getbootstrap.com/docs/3.3/examples/theme/
这个页面是,bootstrap样式表的例样,
http://getbootstrap.com/docs/4.0/examples/
这个页面是,你进去看那个页面合适,你点进去,然后右键查看网页源代码,复制就好了,顺便说一下,别忘了把CSS也复制了.
我们来定义下我们的文章模型,文章内容放到数据库里面,然后通过查询文章标题来,在主页建立文章链接。
app/models.py
class Article(db.Model):
__tablename__ = 'articles'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(64))
content = db.Column(db.Text)
文章模型很简单,一个id,一个文章标题,一个文章的内容这三个字段。
content = db.Column(db.Text),这里,回顾一下或者百度一下SQLAlchemy的列模型。
因为我们文章内容可不是几个字,而是很多上千上万字说不定,所以就不能再用简单的db.String来处理了。
我们使用db.Text这个,他对长文本做了优化.
当我们有了这个数据库的文章模型之后,为了给数据库添加数据,那么我们还需要相对应的表单:
app/admin/forms.py
class PostForm(FlaskForm):
title = StringField('文章标题:', validators=[Required()])
content = TextAreaField('文章内容', validators=[Required()])
submit = SubmitField('发布')
你看注意看变量的名字,我们最可能的让表单和文章模型中的变量去相同的名字,这样方便。
OK,继续。我们有了表单,要在页面中呈现出来。
app/admin/views.py
from ..models import Article
@admin.route('/', methods=['GET', 'POST'])
def index():
form = PostForm()
if not current_user.is_authenticated:
return redirect(url_for('admin.login'))
if form.validate_on_submit():
try:
article = Article(title=form.title.data, content=form.content.data)
db.session.add(article)
form.title.data = ''
form.content.data = ''
flash('发布成功')
except:
flash('文章标题有重复')
return render_template('admin/index.html', form=form)
这段代码也没什么难度,先去创建一个表单form,然后判断一下你是否登录了,没登录的话就会重定向到登录界面。
继续往下,让你提交表单的时候,这里用到了一个try - catch语句,其实这里原因是,我最初想把那个数据库文章模型中title字段设置成unique的,title = db.Column(db.String(64),unique=True),后来想想算了,所不定有相同标题的文章呢。然后就是从表单中获取数据,来构件新的文章,然后存到数据库里面。
flash就是用来做一个提示,方便你自己知道你都干了啥事。
OK,把我们的HTML页面也说一下。
{% extends 'admin/base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block navbar %}
{% endblock %}
{% block page_content %}
{{ wtf.quick_form(form) }}
{% endblock %}
唯一做出了更改的地方就是 {% block page_content %}这里,里面加入了一个表单.
OK,启动一下我们的项目看看效果。
当然你可能会出现一个SQLAlchemy的异常,如何解决:
$ python3 manage.py shell
>>> from manage import *
>>> db.drop_all()
>>> db.create_all()
>>> exit()
更新一下我们的数据库结构,毕竟我们更改了数据库模型,添加了文章这个模型。
注意哦,每当我们更改了app/models.py这个文件,我们最好都要重新设置一下数据库.
我们现在已经可以把文章放到数据库了,现在我们要把数据库的文章显示出来。
在这里,我修改了一下templates/base.html页面:
{% extends 'bootstrap/base.html' %}
{% block title %}Just for fun{% endblock %}
{% block navbar %}
{% endblock %}
{% block content %}
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
{% block page_content %}{% endblock %}
{% block slider %}{% endblock %}
{% endblock %}
只更改了最后,我把
改完templates/base.html,我们在改一下templates/index.html,这是我们的主页,总显示一句话不好看,所以我们改一改。
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block page_content %}
欢迎来到我的blog
技术交流群:630398887
如下内容凑的字数
登鹳雀楼
白日依山尽,黄河入海流。
欲穷千里目,更上一层楼。
论语
子谓公冶长:“可妻也,虽在缧绁之中,非其罪也!”以其子妻之。
子谓南容:“邦有道不废;邦无道免于刑戮。”以其兄之子妻之。
子谓子贱:“君子哉若人!鲁无君子者,斯焉取斯?”
子贡问曰:“赐也何如?”子曰:“女器也。”曰:“何器也?”曰:“瑚琏也。”
或曰:“雍也仁而不佞。”子曰:“焉用佞?御人以口给,屡憎于人。不知其仁,焉用佞?”
子使漆雕开仕,对曰:“吾斯之未能信。”子说。
子曰:“道不行,乘桴浮于海,从我者其由与?”子路闻之喜,子曰:“由也好勇过我,无所取材。”
孟武伯问:“子路仁乎?”子曰:“不知也。”又问,子曰:“由也,千乘之国,可使治其赋也,不知其仁也。”“求也何如?”子曰:“求也,千室之邑、百乘之家,可使为之宰也,不知其仁也。”“赤也何如?”子曰:“赤也,束带立于朝,可使与宾客言也,不知其仁也。”
子谓子贡曰:“女与回也孰愈?”对曰:“赐也何敢望回?回也闻一以知十,赐也闻一以知二。”子曰:“弗如也,吾与女弗如也!”
宰予昼寝,子曰:“朽木不可雕也,粪土之墙不可杇也,于予与何诛?”子曰:“始吾于人也,听其言而信其行;今吾于人也,听其言而观其行。于予与改是。”
子曰:“吾未见刚者。”或对曰:“申枨。”子曰:“枨也欲,焉得刚。”
子贡曰:“我不欲人之加诸我也,吾亦欲无加诸人。”子曰:“赐也,非尔所及也。”
子贡曰:“夫子之文章,可得而闻也;夫子之言性与天道,不可得而闻也。”
子路有闻,未之能行,唯恐有闻。
子贡问曰:“孔文子何以谓之文也?”子曰:“敏而好学,不耻下问,是以谓之文也。”
子谓子产:“有君子之道四焉:其行己也恭,其事上也敬,其养民也惠,其使民也义。”
子曰:“晏平仲善与人交,久而敬之。”
子张问曰:“令尹子文三仕为令尹,无喜色,三已之无愠色,旧令尹之政必以告新令尹,何如?”子曰:“忠矣。”曰:“仁矣乎?”曰:“未知,焉得仁?”“崔子弑齐君,陈文子有马十乘,弃而违之。至于他邦,则曰:‘犹吾大夫崔子也。’违之。之一邦,则又曰:‘犹吾大夫崔子也。’违之,何如?”子曰:“清矣。”曰:“仁矣乎?”曰:“未知,焉得仁?”
{% endblock %}
{% block slider %}
文章列表
{% for article in articles %}
- {{ article.title }}
{% endfor %}
{% endblock %}
当然,大部分内容去百度复制粘贴的,不过这里你要看一下这一段代码。
{% block slider %}
文章列表
{% for article in articles %}
- {{ article.title }}
{% endfor %}
{% endblock %}
我们利用一个for循环,通过视图函数传过来的参数,做了一个文章列表,效果如下:
为了把效果实现出来,我们需要在视图函数中把参数传进来,然后让Jinja2引擎渲染一下。
还记得之前提到Jinja2引擎的时候,它可以想在python里面一样可以解析复杂的数据类型,比如咱这个article。
from ..models import Article
@main.route('/', methods=['GET', 'POST'])
def index():
articles = Article.query.all()
return render_template('index.html', articles=articles)
也很简单拉,把所有文章从数据库获取一下,传进去就好了。
能显示文章列表了,我们需要单独把文章显示出来。
{{ article.title }}
其实阿,这段代码,是我已经把代码都写好了的,因为这个时候你可能还没有把相关的html页面写好。所以说那个
a标签中的href属性可以先不写,然后等会在写就好。
app/templates/article.html
{% extends 'base.html' %}
{% block page_content %}
{{ title }}
{{ content }}
{% endblock %}
文章的页面也很简单,一个标题,一个内容。两个变量。
再看一下视图函数:
@main.route('/article/')
def article(title):
article = Article.query.filter_by(title=title).first()
return render_template('article.html', title=title, content=article.content)
你看这里,还记得动态路由么,这里用到了动态路由,通过文章的标题来从数据库把这篇文章数据获取出来。
然后把标题和文章内容传参到HTML页面就可以了。
这个时候,你就可以把app/templates/index.html页面中那个文章列表的a标签的href属性补全了。
这里说一下,你看啊,我们的功能在不断的增加,可是基本上都没有大幅度改动我们的原先的代码,而是为新功能写好代码,添加进去。这是一个非常好的表现,增加新功能而又不与原先代码有冲突。