Flask框架的学习指南之制作简单blog系统


Posted in Python onNovember 20, 2016

之前写了一篇flask开发环境搭建,今天继续,进行一个实战小项目-blog系统。

blog系统很简单,只有一个页面,然后麻雀虽小五脏俱全。这里目的不是为了做项目而做项目,这篇文章本意是通过这次练习传达以下几个知识点:

1、从全局上了解flask项目的目录结构

2、flask项目的运行机制

3、flask框架实现MVC架构

4、flask-sqlalchemy 操作mysql数据库

一、新建项目:blog系统

在pycharm中,新建flask项目,如下图:

Flask框架的学习指南之制作简单blog系统

完成后的目录结构是这样的:非常简单,一个static文件夹,一个templates文件夹,一个py文件

Flask框架的学习指南之制作简单blog系统

以上的目录结构是flask初始时的结构,这个只能应对很小的项目,对于大型复杂的项目,我们需要引入包的管理,MVC架构设计。

二、目录结构重构,引入包管理

针对上面的结构,在最上层blog3目录下,

   1、新建一个runserver.py文件,作为项目统一入口文件

   2、新建blog文件夹,把已存在的static,templates,blog3.py移到blog文件夹下,然后分别建controller、model文件夹。把blog3.py改名为__init__.py,

现在目录如下所示:

Flask框架的学习指南之制作简单blog系统

这样就相当于一个大工程结构了:

1)最上层blog2目录是项目名称,一个项目下可以包括多个模块,也就是应用,每个应用下有自己的配置文件,初始化文件,MVC架构。

2)runserver.py:与应用模块平级,作为项目启动文件

3)第二级blog2目录:模块名称

       controller目录:MVC中的C,主要存放视图函数

       model目录:MVC中的M,主要存放实体类文件,映射数据库中表

       templates:MVC中的V,存放html文件

       static:静态文件,主要存放css,js等文件

       __init__.py:模块初始化文件,Flask 程序对象的创建必须在 __init__.py 文件里完成, 然后我们就可以安全的导入引用每个包。

       setting.py:配置文件,数据库用户名密码等等

三、开发代码

1、先把项目运行起来:

1) 编写__init__.py文件,创建项目对象,代码如下:

# -*- coding: utf-8 -*-
from flask import Flask

#创建项目对象
app = Flask(__name__)

2) 在runserver.py文件中添加如下代码:

from blog3 import app

@app.route('/')
def hello_world():
  return 'Hello World!'
if __name__ == '__main__':
  app.run(debug=True)

3)运行runserver.py文件:

Flask框架的学习指南之制作简单blog系统

然后在浏览器中输入:http://127.0.0.1:5000/,会显示helloworld字样

Flask框架的学习指南之制作简单blog系统

到这里,项目雏形就可以正常运行了,下面的事情就简单了,添加内容,让项目有血有肉吧。

2、设计数据库

本次练习比较简单,就两个表,一个user表,一个文章表。我们采用python的orm框架flask-sqlalchemy实现表的创建、增删改查功能。

在model文件夹中添加User.py和Category.py文件,内容如下:

1) User.py:

from blog2 import db

class User(db.Model):
  __tablename__ = 'b_user'
  id = db.Column(db.Integer,primary_key=True)
  username = db.Column(db.String(10),unique=True)
  password = db.Column(db.String(16))

  def __init__(self,username,password):
    self.username = username
    self.password = password
  def __repr__(self):
    return '<User %r>' % self.username

2) Category.py

from blog2 import db

class Category(db.Model):
  __tablename__ = 'b_category'
  id = db.Column(db.Integer,primary_key=True)
  title = db.Column(db.String(20),unique=True)
  content = db.Column(db.String(100))

  def __init__(self,title,content):
    self.title = title
    self.content = content
  def __repr__(self):
    return '<Category %r>' % self.title

3)在模块目录blog2下新建setting.py文件,配置数据库连接信息

# _*_ coding: utf-8 _*_

#调试模式是否开启
DEBUG = True

SQLALCHEMY_TRACK_MODIFICATIONS = False
#session必须要设置key
SECRET_KEY='A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

#mysql数据库连接信息,这里改为自己的账号
SQLALCHEMY_DATABASE_URI = "mysql://username:password@ip:port/dbname"

4)让项目读取配置文件

修改__init__.py:添加如下内容(红色部分):

# -*- coding: utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)#import os#print os.environ.keys()#print os.environ.get('FLASKR_SETTINGS')#加载配置文件内容app.config.from_object('blog2.setting')   #模块下的setting文件名,不用加py后缀 app.config.from_envvar('FLASKR_SETTINGS')  #环境变量,指向配置文件setting的路径#创建数据库对象 db = SQLAlchemy(app)

注意:FLASKR_SETTINGS环境变量需要手工单独设置,window下可以在命令行中输入:

E:\workdir\blog2> set FLASKR_SETTINGS=E:\workdir\blog2\blog2\setting.py

或者点击我的电脑-->高级-->环境变量,新建一个。

5)创建数据库和表

windows命令行模式下,cd到项目runserver.py那个目录下,进入python shell下:

输入红色部分:

E:\workdir\blog2>python
Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v.1500 64 bit (AMD64)] on wi
n32
Type "help", "copyright", "credits" or "license" for more information.
>>> from blog2 import db
>>> db.create_all()
>>>
>>>

如果没有任何错误输出代表创建数据库和表成功了。这时我们到数据库中去查看:

Flask框架的学习指南之制作简单blog系统

数据库已经存在了,再看看表情况:发现没有对应的b_user和b_category表。这是为什么呢?是不是没有找到model目录下的两个类呢。问题在于:__init__.py文件没有引入model包,导致__init__.py无法找到实体类。记住:一切模块对象的创建都在__init__.py中完成

在blog2目录下的__init__.py添加如下代码:

#只有在app对象之后声明,用于导入model否则无法创建表
from blog2.model import User,Category

再次运行上面命令:db.create_all()方法。这时表已经创建成功了。

Flask框架的学习指南之制作简单blog系统

3、添加界面模板:如登陆页面,显示blog文章页面,添加blog页面

在templates目录下添加三个html文件:

layout.html:

<!doctype html>
 <title>Flaskr</title>
 <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
 <div class=page>
  <h1>Flaskr</h1>
  <div class=metanav>
  {% if not session.logged_in %}
   <a href="{{ url_for('login') }}">log in</a>
  {% else %}
   <a href="{{ url_for('logout') }}">log out</a>
  {% endif %}
  </div>
  {% for message in get_flashed_messages() %}
   <div class=flash>{{ message }}</div>
  {% endfor %}
  {% block body %}{% endblock %}
 </div>

login.html:

{% extends "layout.html" %}
{% block body %}
 <h2>Login</h2>
 {% if error %}<p class=error><strong>Error:</strong> {{ error }}{% endif %}
 <form action="{{ url_for('login') }}" method=post>
  <dl>
   <dt>Username:
   <dd><input type=text name=username>
   <dt>Password:
   <dd><input type=password name=password>
   <dd><input type=submit value=Login>
  </dl>
 </form>
{% endblock %}

show_entries.html:

{% extends "layout.html" %}
{% block body %}
 {% if session.logged_in %}
  <form action="{{ url_for('add_entry') }}" method='POST' class=add-entry>
   <dl>
    <dt>Title:
    <dd><input type=text size=30 name=title>
    <dt>Text:
    <dd><textarea name=text rows=5 cols=40></textarea>
    <dd><input type=submit value=Share>
   </dl>
  </form>
 {% endif %}
 <ul class=entries>
 {% for entry in entries %}
  <li><h2>{{ entry.title }}</h2>{{ entry.content|safe }}
 {% else %}
  <li><em>Unbelievable. No entries here so far</em>
 {% endfor %}
 </ul>
{% endblock %}

对应static中添加css文件:style.css

body      { font-family: sans-serif; background: #eee; }
a, h1, h2    { color: #377BA8; }
h1, h2     { font-family: 'Georgia', serif; margin: 0; }
h1       { border-bottom: 2px solid #eee; }
h2       { font-size: 1.2em; }

.page      { margin: 2em auto; width: 35em; border: 5px solid #ccc;
         padding: 0.8em; background: white; }
.entries    { list-style: none; margin: 0; padding: 0; }
.entries li   { margin: 0.8em 1.2em; }
.entries li h2 { margin-left: -1em; }
.add-entry   { font-size: 0.9em; border-bottom: 1px solid #ccc; }
.add-entry dl  { font-weight: bold; }
.metanav    { text-align: right; font-size: 0.8em; padding: 0.3em;
         margin-bottom: 1em; background: #fafafa; }
.flash     { background: #CEE5F5; padding: 0.5em;
         border: 1px solid #AACBE2; }
.error     { background: #F0D6D6; padding: 0.5em; }

4、添加业务逻辑

在controller目录下新建blog_message.py文件:

from blog2.model.User import User
from blog2.model.Category import Category
import os

from blog2 import app,db
from flask import request,render_template,flash,abort,url_for,redirect,session,Flask,g

@app.route('/')
def show_entries():
categorys = Category.query.all()
return render_template('show_entries.html',entries=categorys)

@app.route('/add',methods=['POST'])
def add_entry():
if not session.get('logged_in'):
abort(401)
title = request.form['title']
content = request.form['text']
category = Category(title,content)
db.session.add(category)
db.session.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))

@app.route('/login',methods=['GET','POST'])
def login():
error = None
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=request.form['username']).first()
passwd = User.query.filter_by(password=request.form['password']).first()

if user is None:
error = 'Invalid username'
elif passwd is None:
error = 'Invalid password'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('show_entries'))
return render_template('login.html', error=error)

@app.route('/logout')
def logout():
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))

千万不要忘了在模块级目录下(blog2目录)的__init__.py文件引入视图模块,代码如下:

#只有在app对象之后声明,用于导入view模块
from blog2.controller import blog_manage

5、运行项目,效果如下:

1)输入http://127.0.0.1:5000/,正常情况下你的应该是空白的,因为还没有任何数据。

Flask框架的学习指南之制作简单blog系统

2)点击log in

Flask框架的学习指南之制作简单blog系统

忘了告诉你了,你要事先在b_user表中添加一个用户喔,因为登陆要验证用户的,否则你是无法登陆成功的。

3) 添加条目

Flask框架的学习指南之制作简单blog系统 

以上就是这个小项目的所有页面,很简单吧。你一定能搞定!!!

【总结】:通过本次练习,是否对flask框架运行机制有所了解呢,是不是已经有了全局的认识了,如果ok,那么这个小练习就有存在价值了。

参考文献:

         【flask快速入门中文版】http://docs.jinkan.org/docs/flask/

         【flask快速入门英文版】http://flask.pocoo.org/docs/0.11/

         【flask-sqlalchemy中文版】http://www.pythondoc.com/flask-sqlalchemy/index.html

         【flask-sqlalchemy英文版】http://flask-sqlalchemy.pocoo.org/2.1/

Python 相关文章推荐
Python命令行参数解析模块getopt使用实例
Apr 13 Python
python实现类的静态变量用法实例
May 08 Python
python实现在控制台输入密码不显示的方法
Jul 02 Python
Python实现MySQL操作的方法小结【安装,连接,增删改查等】
Jul 12 Python
Python cookbook(数据结构与算法)将序列分解为单独变量的方法
Feb 13 Python
python集合比较(交集,并集,差集)方法详解
Sep 13 Python
10个Python小技巧你值得拥有
Sep 29 Python
python实现本地图片转存并重命名的示例代码
Oct 27 Python
Django之路由层的实现
Sep 09 Python
python实现按关键字筛选日志文件
Dec 24 Python
Python通过4种方式实现进程数据通信
Mar 12 Python
Pyqt助手安装PyQt5帮助文档过程图解
Nov 20 Python
Flask框架的学习指南之开发环境搭建
Nov 20 #Python
Python 描述符(Descriptor)入门
Nov 20 #Python
独特的python循环语句
Nov 20 #Python
【Python】Python的urllib模块、urllib2模块批量进行网页下载文件
Nov 19 #Python
Python基础中所出现的异常报错总结
Nov 19 #Python
轻松掌握python设计模式之策略模式
Nov 18 #Python
轻松掌握python设计模式之访问者模式
Nov 18 #Python
You might like
动态网站web开发 PHP、ASP还是ASP.NET
2006/10/09 PHP
php实现递归与无限分类的方法
2015/02/16 PHP
PHP+Mysql+jQuery文件下载次数统计实例讲解
2015/10/10 PHP
Yii2单元测试用法示例
2016/11/12 PHP
PHP编写daemon process 实例详解
2016/11/13 PHP
PHP laravel中的多对多关系实例详解
2017/06/07 PHP
解决form中action属性后面?传递参数 获取不到的问题
2017/07/21 PHP
PHP设计模式之简单工厂和工厂模式实例分析
2019/03/25 PHP
用javascript动态调整iframe高度的代码
2007/04/10 Javascript
javascript之大字符串的连接的StringBuffer 类
2007/05/08 Javascript
javascript窗口宽高,鼠标位置,滚动高度(详细解析)
2013/11/18 Javascript
jQuery的3种请求方式$.post,$.get,$.getJSON
2014/03/28 Javascript
jQuery队列操作方法实例
2014/06/11 Javascript
jQuery1.9+中删除了live以后的替代方法
2016/06/17 Javascript
关于两个jQuery(js)特效冲突的bug的解决办法
2016/09/04 Javascript
jQuery插件FusionCharts绘制ScrollColumn2D图效果示例【附demo源码下载】
2017/03/22 jQuery
使用原生js+canvas实现模拟心电图的实例
2017/09/20 Javascript
详解Puppeteer 入门教程
2018/05/09 Javascript
微信小程序实现多选框全选与反全选及购物车中删除选中的商品功能
2019/12/17 Javascript
记录一次websocket封装的过程
2020/11/23 Javascript
轻松实现python搭建微信公众平台
2016/02/16 Python
基于Python的接口测试框架实例
2016/11/04 Python
Python实现利用最大公约数求三个正整数的最小公倍数示例
2017/09/30 Python
Django1.9 加载通过ImageField上传的图片方法
2018/05/25 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
Python实现八皇后问题示例代码
2018/12/09 Python
Linux系统下升级pip的完整步骤
2021/01/31 Python
HTML5图片层叠的实现示例
2020/07/07 HTML / CSS
船餐厅和泰晤士河餐饮游轮:Bateaux London
2018/03/19 全球购物
详细的大学生创业计划书模板
2014/01/27 职场文书
毕业实习评语
2014/02/10 职场文书
暑期教师培训方案
2014/06/07 职场文书
2015年中学元旦晚会活动方案
2014/12/09 职场文书
初中语文教学随笔
2015/08/15 职场文书
小公司融资,商业计划书的8切记
2019/07/15 职场文书
pandas提升计算效率的一些方法汇总
2021/05/30 Python