1. 程式人生 > >python筆記-flask-migrate和flask-script

python筆記-flask-migrate和flask-script

flask-migrate和flask-script應用-實現資料庫修改

#     命令列管理檔案:
#           - 包含資料庫遷移命令
#           - 包含資料庫修改命令

from flask_migrate import  Migrate, MigrateCommand
from flask_script import  Shell, Manager
from models import app, db, User, Department
# 用來管理命令的物件, Manager用來跟蹤所有名林不過並處理他們如何從命令列呼叫;
manager = Manager(app)
migrate = Migrate(app, db)
# 新增一條資料庫遷移管理的命令
manager.add_command('db', MigrateCommand)

在命令列中執行:

python manager.py db init #建立遷移倉庫 python manager.py db migrate “對這次遷移的說明” #生成遷移檔案 python manager.py db upgrade # 將遷移檔案對映的資料庫中,最終改變資料庫結構 python manager.py db history #檢視遷移歷史 python manager.py db downgrade base #返回base時資料庫結構

用命令對資料庫內容進行查詢和新增

from flask_migrate import  Migrate, MigrateCommand
from flask_script import  Shell, Manager
from models import app, db, User, Department
# 用來管理命令的物件, Manager用來跟蹤所有名林不過並處理他們如何從命令列呼叫;
manager = Manager(app)
migrate = Migrate(app, db)
# 新增一條資料庫遷移管理的命令
manager.add_command('db', MigrateCommand)

#  新增一條命令, 可以顯示所有的使用者
@manager.command
def showUser():
    """顯示所有的使用者"""
    users = User.query.all()
    print(users[:5])

#  新增一條命令, 可以顯示所有的使用者
@manager.command
def showDepart():
    """顯示所有的部門"""
    deaprts  = Department.query.all()
    print(deaprts)

 # 新增部門
@manager.option('-n', '--name', help="部門名稱")
def add_depart(name):
    try:
        depart1 = Department(name=name)
        db.session.add(depart1)
        db.session.commit()
    except Exception:
        print("建立部門失敗!")
    else:
        print("建立部門%s成功!" %(name))
   
  if __name__ == "__main__":
    # 準備
    manager.run()

應用案例-實現人物清單管理

base.html:


{% extends "bootstrap/base.html" %}

{% block styles %}
    {{ super() }}
    <link rel="stylesheet" href="../static/css/main.css">
{% endblock %}


{% block navbar %}
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
               <a class="navbar-brand" href="index.html"></a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                     <li><a href="#"></a></li>
                     <li><a href="#"></a></li>
                    <li><a href="#">首頁<span class="sr-only">(current)</span></a></li>
                    <li><a href="#">新聞</a></li>
                    <li><a href="#">國際</a></li>
                    <li><a href="#">國內</a></li>
                    <li><a href="/sysinfo/">系統資訊</a></li>
                    <li><a href="#">登陸使用者</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right">


                    {% if 'user' in session %}
                        <li><a href="login.html"><span class="glyphicon glyphicon-user"></span>
                            &nbsp;&nbsp; {{ session.user }}</a></li>
                        <li><a href="/logout/"><span class="glyphicon glyphicon-log-in"></span>
                            &nbsp;&nbsp; 登出 </a></li>


                    {% else %}

                        <li><a href="/login/"><span class="glyphicon glyphicon-log-in"></span>
                            &nbsp;&nbsp;登陸</a></li>
                        <li><a href="/register/"><span class="glyphicon glyphicon-log-out"></span>
                        &nbsp;&nbsp;註冊</a></li>
                    {% endif %}



                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
{% endblock %}



{% block content %}
    {#定義屬於自己的block#}
    {% block  newcontent %}

    {% endblock %}

    {% block footer %}

        <div class="footer">


            京ICP備11008151號京公網安備11010802014853

        </div>

    {% endblock %}
{% endblock %}

list.html:

{% extends 'base.html' %}

{% block newcontent %}
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            /*新增任務*/
            <form class="form-horizontal" action="/todo/add/" method="post">
                <div class="form-group">
                    {#  新增框                   #}
                    <div class="col-sm-9">
                        <input type="text" class="form-control" placeholder="請新增任務" required="required"
                               name="todo_name">
                    </div>
                    {#    選擇框              #}
                    <div class="col-sm-2">
                        <select class="form-control" name="part">
                            {% for part in parts %}
                                <option value="{{ part.id }}">{{ part.name }}</option>
                            {% endfor %}
                        </select>
                    </div>

                    {#   新增的按鈕              #}
                    <div class="col-sm-1">
                        <input type="submit" class="btn btn-success" value="新增任務">
                    </div>
                </div>

            </form>


            /*任務顯示*/
            <h1>新增任務</h1>
            <table class="table table-bordered">
                <tr>
                    <td>任務內容</td>
                    <td>建立時間</td>
                    <td>狀態</td>
                    <td>所屬部門</td>
                    <td>操作</td>
                </tr>
                {% for todo in todos %}
                    <tr>
                        <td>{{ todo.name }}</td>
                        <td>{{ todo.add_time }}</td>
                        {#        #}
                        <td>
                            {% if todo.status %}
                                 <a href="/todo/undo/{{  todo.id }}/" class="btn btn-sm btn-success" role="button"><span
                            class="glyphicon glyphicon-ok"></span> 已完成</a>

                            {% else %}
                                <a href="/todo/done/{{  todo.id }}/" class="btn btn-sm btn-warning" role="button"><span
                            class="glyphicon glyphicon-remove"></span> 未完成</a>

                            {% endif %}

                        </td>
                        <td>{{ todo.department.name }}</td>
                        <td><a href="/todo/delete/{{  todo.id }}/" class="btn btn-sm btn-danger" role="button"><span
                            class="glyphicon glyphicon-remove"></span> 刪除</a></td>
                    </tr>

                {% endfor %}


            </table>
        </div>
    </div>

{% endblock %}
from datetime import datetime
from flask import Flask
from flask_sqlalchemy import  SQLAlchemy
from flask_bootstrap import  Bootstrap

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]/Todo'
# SQLAlchemy 將會追蹤物件的修改並且傳送訊號。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
bootstrap = Bootstrap(app)
app.config['SECRET_KEY'] = 'westos'
#  1). 面向物件方式建立表
#  2). 分析關係:
#       部門和使用者: 一對多
#       使用者和任務: 一對多的關係
#       使用者和使用者登入日誌: 一對多的關係
#  實現一對多(Role(1): User(n))的關係
#   - 多的一端寫外來鍵
#   - 少的一端寫反向引用

class User(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    # unique:使用者名稱唯一, nullable=False指使用者名稱不能為空;
    name = db.Column(db.String(50), unique=True, nullable=False)
    pwd = db.Column(db.String(100))
    email = db.Column(db.String(30), unique=True)
    phone = db.Column(db.String(30), unique=True)
    info = db.Column(db.Text)  # 個人簡介
    add_time = db.Column(db.DateTime, default=datetime.now())   # 建立時間
    department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
    todos = db.relationship('Todo', backref='user')
    userlogs = db.relationship('Userlog', backref='user')
    # 部門id與其他表關聯,不能隨便寫

    def __repr__(self):
        return  '<User: %s>' %(self.name)


# 部門
class Department(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(50), unique=True, nullable=False)
    #  反向引用: user就包含一個屬性, department
    users = db.relationship('User', backref='department')
    todos = db.relationship('Todo', backref='department')
    def __repr__(self):
        return  '<Department: %s>' %(self.name)

class Todo(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(200), nullable=False)
    add_time = db.Column(db.DateTime, default=datetime.now())  # 建立時間
    status = db.Column(db.Boolean, default=False)  # 任務狀態, 預設為Flase(未完成)
    department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
    user_id = db.Column(db.Integer,db.ForeignKey('user.id') )

    def __repr__(self):
        return '<Todo: %s>' % (self.id)

# 使用者登入日誌
class Userlog(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    add_time = db.Column(db.DateTime, default=datetime.now())  # 建立時間
    ip = db.Column(db.String(200), nullable=False) # 登入ip
    area =  db.Column(db.String(200))  # 使用者登入地點
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))  # 外來鍵


    def __repr__(self):
        return '<Userlog: %s>' % (self.ip)
from flask import render_template, request, redirect, url_for, session

from models import app, Todo, db, Department,User
from mDB import isPasswdOk,isUserExist,addUser
from forms import LoginForm,RegisterForm
@app.route('/')
def index():
    return render_template('base.html')
@app.route('/register/')
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        user = request.form('user')
        passwd = request.form('passwd')
    return render_template('register.html')

@app.route('/login/',methods=['GET','POST'])
def login():
    form = LoginForm()
    # 如果是post方法並且表單驗證通過的話, 返回True;
    if form.validate_on_submit():
        # 1). 獲取使用者提交的表單資訊
        # print(form.data) 是字典型別, 內容如下:
        # {'user': 'westos', 'passwd': 'westos', 'submit': True }
        user = form.data['user']
        passwd = form.data['passwd']
        # 2. 判斷使用者名稱和密碼是否正確

        if isPasswdOk(user, passwd):
            # 將使用者名稱和密碼資訊儲存到session中;
            session['user'] = user
            session['passwd'] = passwd
            # 如果登陸成功, 跳轉到主頁;
            return redirect(url_for('todo_list'))
        else:
            # 如果登陸失敗, 重新登陸;
            return render_template('login.html',form=form,  message="使用者名稱或者密碼錯誤")
    return  render_template('login.html', form=form)
@app.route('/logout/')
def logout():
    session.pop('user',None)
    session.pop('passwd',None)
    return redirect(url_for('todo_list'))
# 任務的增刪改查
@app.route('/todo/add/', methods=['POST'])
def todo_add():
    # 獲取提交的任務資訊
    name = request.form['todo_name']
    part = request.form['part']
    # 新增完成之後, 返回任務列表顯示頁面
    u = User.query.filter_by(name=session['user']).first()
    id = u.id
    todo = Todo(name=name, department_id=part, user_id=id)
    db.session.add(todo)
    db.session.commit()

    return  redirect(url_for('todo_list'))


@app.route('/todo/delete/<int:id>/')
def todo_delete(id):
    u = Todo.query.filter_by(id=id).first()
    db.session.delete(u)
    db.session.commit()
    return redirect(url_for('todo_list'))

@app.route('/list/')
def todo_list():
    # 1). 從資料庫中查詢
    todos = Todo.query.all()
    parts = Department.query.all()

    return  render_template('list.html',
                            todos = todos,
                            parts=parts)

# 修改任務的狀態(變成已完成狀態/變成未完成狀態)
@app.route('/todo/undo/<int:id>/')
def undo(id):
    todo = Todo.query.filter_by(id=id).first()
    todo.status = False
    db.session.commit()
    # 更新狀態後, 返回任務列表頁
    return redirect(url_for('todo_list'))

@app.route('/todo/done/<int:id>/')
def done(id):
    todo = Todo.query.filter_by(id=id).first()
    todo.status = True
    db.session.commit()
    # 更新狀態後, 返回任務列表頁
    return redirect(url_for('todo_list'))

# 專案真實執行指令碼

from  models import  app
# 匯入編寫的檢視函式和路由
from views import  *

if __name__ == '__main__':
    app.run()