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怎么学好python?
Oct 07 Python
在Python中操作时间之strptime()方法的使用
Dec 30 Python
Python3随机漫步生成数据并绘制
Aug 27 Python
python中的不可变数据类型与可变数据类型详解
Sep 16 Python
Python动态声明变量赋值代码实例
Dec 30 Python
Python插入Elasticsearch操作方法解析
Jan 19 Python
jupyter notebook 重装教程
Apr 16 Python
Django模板获取field的verbose_name实例
May 19 Python
Python过滤序列元素的方法
Jul 31 Python
Flask-SocketIO服务端安装及使用代码示例
Nov 26 Python
python 基于UDP协议套接字通信的实现
Jan 22 Python
python 如何做一个识别率百分百的OCR
May 29 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
Wordpress php 分页代码
2009/10/21 PHP
10个可以简化php开发过程的MySQL工具
2010/04/11 PHP
php switch语句多个值匹配同一代码块应用示例
2014/07/29 PHP
给ECShop添加最新评论
2015/01/07 PHP
php给数组赋值的实例方法
2019/09/26 PHP
php框架知识点的整理和补充
2021/03/01 PHP
js的event详解。
2006/09/06 Javascript
JavaScript 自动完成脚本整理(33个)
2009/10/20 Javascript
JAVASCRIPT实现的WEB页面跳转以及页面间传值方法
2010/05/13 Javascript
7个JS基础知识总结
2014/03/05 Javascript
javascript替换已有元素replaceChild()使用介绍
2014/04/03 Javascript
javascript 模拟坦克大战游戏(html5版)附源码下载
2014/04/08 Javascript
javascript中scrollTop详解
2015/04/13 Javascript
jQuery EasyUI 布局之动态添加tabs标签页
2015/11/18 Javascript
javascript高级选择器querySelector和querySelectorAll全面解析
2016/04/07 Javascript
jQuery绑定自定义事件的魔法升级版
2016/06/30 Javascript
深入理解JavaScript函数参数(推荐)
2016/07/26 Javascript
JavaScript lodash常见用法系列小结
2016/08/24 Javascript
js获取ip和地区
2017/03/10 Javascript
JS 60秒后重新发送验证码的实例讲解
2017/07/26 Javascript
JS基于开关思想实现的数组去重功能【案例】
2019/02/18 Javascript
node.JS事件机制与events事件模块的使用方法详解
2020/02/06 Javascript
Vue Router 实现动态路由和常见问题及解决方法
2020/03/06 Javascript
[01:13:08]2018DOTA2亚洲邀请赛4.6 淘汰赛 mineski vs LGD 第二场
2018/04/10 DOTA
python使用sorted函数对列表进行排序的方法
2015/04/04 Python
Python实现删除当前目录下除当前脚本以外的文件和文件夹实例
2015/07/27 Python
Python中super()函数简介及用法分享
2016/07/11 Python
python读取文件名称生成list的方法
2018/04/27 Python
Python使用Pandas读写Excel实例解析
2019/11/19 Python
keras的load_model实现加载含有参数的自定义模型
2020/06/22 Python
岗位职责的构建方法
2014/02/01 职场文书
副总经理岗位职责
2014/03/16 职场文书
文明美德伴我成长演讲稿
2014/05/12 职场文书
职业道德模范事迹材料
2014/08/24 职场文书
全国优秀教师事迹材料
2014/08/26 职场文书
个人遵守党的政治纪律情况对照检查材料思想汇报
2014/09/25 职场文书