flaskStudy
环境:anaconda (python3.7), windows10
hello world
首先创建三个目录
- app
- app/templates :放模板文件(html)
- app/static:静态资源(图片,css,js等)
- 创建几个文件
- run.py:项目启动文件(入口文件)
- migrate.py:数据库迁移文件
- app/__init__.py
- app/config.py:配置文件
- app/models.py:模型文件
- app/views.py:视图文件(将来主要的逻辑处理文件)
创建完成后就是这样的:
__init__.py中的代码:
from flask import Flask app = Flask(__name__) app.config.from_object('app.config') from app import views, models
views.py:
from app import app @app.route('/') @app.route('/index') def index(): return 'hello world'
run.py:
from app import app app.run(debug=True)
然后运行run.py
你就可以按照提示访问了
Flask 中的数据库
我们将使用 Flask-SQLAlchemy 扩展来管理我们应用程序的数据。这个扩展封装了 SQLAlchemy 项目,这是一个 对象关系映射器 或者 ORM。
ORMs 允许数据库应用程序与对象一起工作,而不是表以及 SQL。执行在对象的操作会被 ORM 翻译成数据库命令。这就意味着我们将不需要学习 SQL,我们将让 Flask-SQLAlchemy 代替 SQL。
conda config --add channels conda-forge
conda install flask-sqlalchemy
迁移
我见过的大多数数据库教程会涉及到创建和使用一个数据库,但没有充分讲述随着应用程序扩大更新数据库的问题。通常情况下,每次你需要进行更新,你最终不得不删除旧的数据库和创建一个新的数据库,并且失去了所有的数据。如果数据不能容易地被重新创建,你可能会被迫自己编写导出和导入脚本。
幸运地,我们还有一个更好的选择。
我们将使用 SQLAlchemy-migrate 来跟踪数据库的更新。它只是在开始建立数据库的时候多花费些工作,这只是很小的代价,以后就再不用担心人工数据迁移了
conda install flask-migrate
博客和后台
包含一个博客上传的后台,首页列表,详情页:
__init__.py:
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate import os, pymysql pymysql.install_as_MySQLdb() app = Flask(__name__) app.config.from_object('app.config') db = SQLAlchemy(app) migrate = Migrate(app, db) from app import views, models from app import adminviews
config.py:
import os basedir = os.path.abspath(os.path.dirname(__file__)) MYSQL_HOST = "127.0.0.1" MYSQL_USER = "root" MYSQL_PWD = "123456" MYSQL_DB = "test" SQLALCHEMY_DATABASE_URI = "mysql://" + MYSQL_USER + ":" + MYSQL_PWD + "@" + MYSQL_HOST + "/" + MYSQL_DB SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository') SQLALCHEMY_TRACK_MODIFICATIONS = True UPLOAD_FOLDER = os.path.join(basedir, 'static/images') IMGURL = 'http://10.0.0.87:5000/' SECRET_KEY = '_5#y2L"F4Q8z xec]/'
adminviews.py
from app import app, models from flask import (render_template, request, jsonify, flash, get_flashed_messages) from werkzeug.utils import secure_filename import json import os import uuid from . import db ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) @app.route('/') @app.route('/admin/blogUpload', methods=['GET', 'POST']) def blogUploadView(): if request.method == 'POST': if request.form['content'].strip() == '' or request.form['category'].strip() == '' or request.form[ 'title'].strip() == '': print(request.form['content']) flash('信息不全') else: try: blog = models.Blog(**request.form) db.session.add(blog) db.session.commit() flash('成功') except: db.session.rollback() flash('信息有误') categorys = models.Category.query.all() return render_template('blogUpload.html', categorys=categorys) @app.route('/img/upload', methods=['GET', 'POST']) def imgUpload(): if request.method == 'POST': if 'file' not in request.files: return jsonify({'code': 0, 'msg': '失败'}) file = request.files['file'] if file.filename == '': return jsonify({'code': 0, 'msg': '失败'}) if allowed_file(file.filename): filename = str(uuid.uuid1()) + secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) link = app.config['IMGURL'] + filename rsp = {'errno': 0, 'data': [link]} return jsonify(rsp) return jsonify({'code': 0, 'msg': '失败'}) def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
models.py:
from app import db class User(db.Model): id = db.Column(db.Integer, primary_key=True) nickname = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) posts = db.relationship('Post', backref='author', lazy='dynamic') def __repr__(self): return '<User %r>' % (self.nickname) class Post(db.Model): id = db.Column(db.Integer, primary_key=True) body = db.Column(db.String(140)) timestamp = db.Column(db.DateTime) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) def __repr__(self): return '<Post %r>' % (self.body) class Category(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255)) def __repr__(self): return '<Category %r>' % (self.name) class Blog(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(225), unique=True) category = db.Column(db.Integer, db.ForeignKey('category.id')) content = db.Column(db.Text) def __int__(self, title, category, content): self.title = title self.category = category self.content = content def __repr__(self): return '<Blog %r>' % (self.title)
views.py:
from app import app from flask import render_template from app import models from bs4 import BeautifulSoup @app.route('/') @app.route('/index') def index(): blogs = models.Blog.query.all() blogs1 = list() for bl in blogs: soup = BeautifulSoup(bl.content, "html.parser") bf = soup.get_text()[0:10] + '...' blogs1.append({"title": bl.title, "bf": bf, "id": bl.id}) return render_template("index.html", blogs=blogs1) @app.route('/about/<int:id>') def about(id): about = models.Blog.query.filter_by(id=id).first() return render_template("about.html", about=about)
base.html:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>首页_杨青个人博客 - 一个站在web前端设计之路的女技术员个人博客网站</title> <meta name="keywords" content="个人博客,杨青个人博客,个人博客模板,杨青" /> <meta name="description" content="杨青个人博客,是一个站在web前端设计之路的女程序员个人网站,提供个人博客模板免费资源下载的个人原创网站。" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="{{ url_for('static',filename='css/base.css') }}" rel="stylesheet"> <link href="{{ url_for('static',filename='css/index.css') }}" rel="stylesheet"> <link href="{{ url_for('static',filename='css/m.css') }}" rel="stylesheet"> <script src="{{ url_for('static',filename='js/jquery.min.js') }}" type="text/javascript"></script> <script type="text/javascript" src="{{ url_for('static',filename='js/comm.js') }}"></script> <!--[if lt IE 9]> <script src="{{ url_for('static',filename='js/modernizr.js') }}"></script> <![endif]--> {% block head %} {% endblock %} </head> <body> <header class="header-navigation" id="header"> <nav><div class="logo"><a href="/">杨青个人博客</a></div> <h2 id="mnavh"><span class="navicon"></span></h2> <ul id="starlist"> <li><a href="index.html">网站首页</a></li> <li><a href="share.html">我的相册</a></li> <li><a href="list.html">我的日记</a></li> <li><a href="about.html">关于我</a></li> <li><a href="gbook.html">留言</a></li> <li><a href="info.html">内容页</a></li> <li><a href="infopic.html">内容页</a></li> </ul> </nav> </header> <article> <aside class="l_box"> <div class="about_me"> <h2>关于我</h2> <ul> <i><img src="images/4.jpg"></i> <p><b>杨青</b>,一个80后草根女站长!09年入行。一直潜心研究web前端技术,一边工作一边积累经验,分享一些个人博客模板,以及SEO优化等心得。</p> </ul> </div> <div class="wdxc"> <h2>我的相册</h2> <ul> <li><a href="/"><img src="images/7.jpg"></a></li> <li><a href="/"><img src="images/8.jpg"></a></li> <li><a href="/"><img src="images/9.jpg"></a></li> <li><a href="/"><img src="images/10.jpg"></a></li> <li><a href="/"><img src="images/11.jpg"></a></li> <li><a href="/"><img src="images/12.jpg"></a></li> </ul> </div> <div class="search"> <form action="/e/search/index.php" method="post" name="searchform" id="searchform"> <input name="keyboard" id="keyboard" class="input_text" value="请输入关键字词" style="color: rgb(153, 153, 153);" onfocus="if(value=='请输入关键字词'){this.style.color='#000';value=''}" onblur="if(value==''){this.style.color='#999';value='请输入关键字词'}" type="text"> <input name="show" value="title" type="hidden"> <input name="tempid" value="1" type="hidden"> <input name="tbname" value="news" type="hidden"> <input name="Submit" class="input_submit" value="搜索" type="submit"> </form> </div> <div class="fenlei"> <h2>文章分类</h2> <ul> <li><a href="/">学无止境(33)</a></li> <li><a href="/">日记(19)</a></li> <li><a href="/">慢生活(520)</a></li> <li><a href="/">美文欣赏(40)</a></li> </ul> </div> <div class="tuijian"> <h2>站长推荐</h2> <ul> <li><a href="/">你是什么人便会遇上什么人</a></li> <li><a href="/">帝国cms 列表页调用子栏目,没有则不显示栏目名称</a></li> <li><a href="/">第二届 优秀个人博客模板比赛参选活动</a></li> <li><a href="/">个人博客模板《绅士》后台管理</a></li> <li><a href="/">你是什么人便会遇上什么人</a></li> <li><a href="/">帝国cms 列表页调用子栏目,没有则不显示栏目名称</a></li> <li><a href="/">第二届 优秀个人博客模板比赛参选活动</a></li> <li><a href="/">个人博客模板《绅士》后台管理</a></li> </ul> </div> <div class="links"> <h2>友情链接</h2> <ul> <a href="http://www.yangqq.com">杨青个人博客</a> <a href="http://www.yangqq.com">杨青博客</a> </ul> </div> <div class="guanzhu"> <h2>关注我 么么哒</h2> <ul> <img src="images/wx.jpg"> </ul> </div> </aside> {% block main %}{% endblock %} </article> <footer> <p>Design by <a href="http://www.yangqq.com" target="_blank">杨青个人博客</a> <a href="/">蜀ICP备11002373号-1</a></p> </footer> <a href="#" class="cd-top">Top</a> </body> {% block js %}{% endblock %} </html>
index.html
{% extends 'base.html' %} {% block main %} <main class="r_box"> <li> {% for bl in blogs %} <h3><a href="/about/{{ bl.id }}">{{ bl.title }}</a></h3> <p>{{ bl.bf }}</p> {% endfor %} </li> </main> {% endblock %}
about.html
{% extends 'base.html' %} {% block main %} <main class="r_box"> <div class="about"> {{ about.content | safe }} </div> </main> {% endblock %}
blogUpload.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <link rel="stylesheet" href="{{ url_for('static',filename='bootstrap337/css/bootstrap.css') }}"> <link rel="stylesheet" href="{{ url_for('static',filename='editor/release/wangEditor.css') }}"> <script src="{{ url_for('static',filename='js/jquery.min.js') }}" type="text/javascript"></script> <script src="{{ url_for('static',filename='bootstrap337/js/bootstrap.js') }}" type="text/javascript"></script> <script src="{{ url_for('static',filename='editor/release/wangEditor.js') }}" type="text/javascript"></script> </head> <body> <div class="container-fluid"> <div class="row"> <form class="form-horizontal" action="/admin/blogUpload" method="post"> {% with messages = get_flashed_messages() %} <div class="form-group"> {% for msg in messages %} <span>{{ msg }}</span> {% endfor %} </div> {% endwith %} <div class="form-group"> <label class="col-sm-2 control-label">标题</label> <div class="col-sm-10"> <input type="text" class="form-control" name="title"> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">分类</label> <div class="col-sm-10"> <select name="category" class="form-control"> {% for category in categorys %} <option value="{{ category.id }}">{{ category.name }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">内容</label> <div class="col-sm-10"> <input type="hidden" class="form-control" name="content" id="content"> <div id="edit"></div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default" id="submit">save</button> </div> </div> </form> </div> </div> <script type="text/javascript"> var E = window.wangEditor var editor = new E('#edit') editor.customConfig.menus = [ 'head', // 标题 'bold', // 粗体 'italic', // 斜体 'underline', // 下划线 'strikeThrough', // 删除线 'foreColor', // 文字颜色 'backColor', // 背景颜色 'link', // 插入链接 'list', // 列表 'quote', // 引用 'image', // 插入图片 'video', // 插入视频 'undo', // 撤销 'redo' // 重复 ] editor.customConfig.uploadImgServer = '/img/upload' editor.customConfig.uploadFileName = 'file' editor.create() $('#submit').click(function() { var info = editor.txt.html(); if(!info){ alert('详情不能为空'); return false; } $('#content').val(info); return true; }) </script> </body> </html>
相关代码在https://github.com/LeeDF/flaskStudy