那些年咱們學Flask-SQLAlchemy,實現數據庫操做,分頁等功能

那些年咱們學Flask-SQLAlchemyhtml

實現數據庫操做,分頁等功能 python



Flask-SQLAlchemy庫讓flask更方便的使用SQLALchemy,是一個強大的關係形數據庫框架,既可使用orm方式操做數據庫,也可使用原始的SQL命令.mysql

Flask-Migrate 是一個數據遷移框架,須要經過Flask-script庫來操做.web



一.配置Flask-SQLAlchemy

程序使用的數據庫地址須要配置在SQLALCHEMY_DATABASE_URI中,SQLALchemy支持多種數據庫,配置格式以下:sql

  Postgres:數據庫

  postgresql://scott:tiger@localhost/mydatabase

  MySQL:flask

  mysql://scott:tiger@localhost/mydatabase

  Oracle:bootstrap

  oracle://scott:tiger@127.0.0.1:1521/sidname

  SQLite:api

  sqlite:////absolute/path/to/foo.db

db是SQLALchemy類的實例,表示程序使用的數據庫,爲用戶提供Flask-SQLALchemy的全部功能session

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
#配置數據庫地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost:3306/DB_name?charset=utf8'
#該配置爲True,則每次請求結束都會自動commit數據庫的變更
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)
#也能夠db = SQLAlchemy()      db.init_app(app)

二.定義模型

Flask-SQLALchemy使用繼承至db.Model的類來定義模型,如:

class User(db.Model, UserMixin):#UserMixin是Flask-Login庫中所須要的
    __tablename__ = 'users'
    #每一個屬性定義一個字段
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(64),unique=True)
    password = db.Column(db.String(64))

    #定製顯示的格式    
    def __repr__(self):        
        return '<User %r>' % self.username


定義完須要在Python Shell中導入db,調用db.create_all()來建立數據庫

(1)經常使用字段選項:

  primary_key 設置主鍵

  unique 是否惟一

  index 是否建立索引

  nullable 是否容許爲空

  default 設置默認值,能夠傳入函數的引用 如傳入 datetime.datetime.utcnow 則每次建立時時間都是最新時間

三.增刪查改

(1) 插入數據:

from app.models import User
from app import db

#建立一個新用戶
u = User()
u.username = 'abc'
u.password = 'abc'

#將用戶添加到數據庫會話中
db.session.add(u)

#將數據庫會話中的變更提交到數據庫中,若是不Commit,數據庫中是沒有改動的
db.session.commit()

(2)查找數據:

#返回全部用戶保存到list中
user_list = User.query.all()

#查找username爲abc的第一個用戶,返回用戶實例
u = User.query.filter_by(username='abc').first()

#模糊查找用戶名以c結尾的全部用戶
user_list  = User.query.filter(username.endswith('c')).all()

#查找用戶名不是abc的用戶
u = User.query.filter(username != 'abc').first()


(3)刪除數據:

user = User.query.first()
db.session.delete(user)
db.session.commit()


(4)修改數據:

u = User.query.first()
u.username = 'Mackie'
db.session.commit()


四.一對多關係

個人理解是:在多的一邊定義外鍵,而relathonship()函數是用來創建關係的,能夠只在一邊定義,也能夠兩邊都使用(只在一邊使用時加上了backref選項等同於兩邊都使用)

class Person(db.Model):
        __tablename__ = 'persons'
        
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))    
    #backref將在Address表中建立個名爲persons的Person引用,以後可使用address.persons         #訪問這個地址的全部人
    addresses = db.relationship('Address', backref='persons',lazy='dynamic')

class Address(db.Model):
        __tablename__ = 'address'
        
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))    
    #在多的一邊使用db.ForeignKey聲明外鍵
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))


五.多對多關係

多對多關係能夠分解爲原表和關聯表之間兩個多對一關係,以下代碼創建了學生與所選課程之間的關係:

#建立關聯表,兩個字段的外鍵是另兩個表,一個學生對應多個關聯表,一個關聯表對應多個課程
registrations = db.Table('registrations',
                         db.Column('student_id',db.Integer,db.ForeignKey('students.id')),
                         db.Column('class_id',db.Integer,db.ForeignKey('classes.id'))
                         )

class Student(db.Model):
    __tablename__ = 'students'
    id = db.Column(db.Integer,primary_key=True,)
    name = db.Column(db.String)
    classes = db.relationship('Class',
                              secondary = registrations, #關聯表,只須要在一個表創建關係,sqlalchemy會負責處理好另外一個表
                              backref = db.backref('students',lazy='dynamic'),
                              lazy = 'dynamic')


class Class(db.Model):
    __tablename__ = 'classes'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)


多對多的使用:

#學生1增長一門選課
student1.classes.append(class1)
#學生1退選class1
student1.classes.remove(class1)
#學生1所選課程,因爲指定了lazy='dynamic'因此沒有直接返回列表,而須要使用.all()
student1.classes.all()


六.分頁導航

Flask-SQLALchemy的Pagination對象能夠方便的進行分頁,

對一個查詢對象調用pagenate(page, per_page=20, error_out=True)函數能夠獲得pagination對象,第一個參數表示當前頁,第二個參數表明每頁顯示的數量,error_out=True的狀況下若是指定頁沒有內容將出現404錯誤,不然返回空的列表

#從get方法中取得頁碼
page = request.args.get('page', 1, type = int)
#獲取pagination對象
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=10, error_out = False)

#pagination對象的items方法返回當前頁的內容列表
    posts = pagination.items


pagination對象經常使用方法:

has_next :是否還有下一頁

has_prev :是否還有上一頁

items : 返回當前頁的全部內容

next(error_out=False) : 返回下一頁的Pagination對象

prev(error_out=False) : 返回上一頁的Pagination對象

page : 當前頁的頁碼(從1開始)

pages : 總頁數

per_page : 每頁顯示的數量

prev_num : 上一頁頁碼數

next_num :下一頁頁碼數

query :返回 建立這個Pagination對象的查詢對象

total :查詢返回的記錄總數

iter_pages(left_edge=2, left_current=2, right_current=5, right_edge=2)

在模版中使用

方法一:

{% macro render_pagination(pagination, endpoint) %}
  <div class=pagination>
  {%- for page in pagination.iter_pages() %}
    {% if page %}
      {% if page != pagination.page %}
        <a href="{{ url_for(endpoint, page=page) }}">{{ page }}</a>
      {% else %}
        <strong>{{ page }}</strong>
      {% endif %}
    {% else %}
      <span class=ellipsis>…</span>
    {% endif %}
  {%- endfor %}
  </div>
{% endmacro %}


方法二:jinjia2渲染+bootstrap模板

<!-- 建立頁碼-->
<ul class="pagination">
{#上一頁#}
    {%  if pagination.has_prev  %}
        <li><a href="{{ url_for('UserAdmin',page=pagination.prev_num) }}">&laquo;</a></li>
    {% endif %}

    {#頁碼#}
    {% set page_now = pagination.page  %}
    {% set page_count = pagination.pages %}
    {% if pagination.pages <= 5 %}
        {% for p in pagination.iter_pages() %}
                {% if p == pagination.page %}
                  <li ><a style="background-color: darkgray;opacity: 0.7;color: black" href="{{ url_for('UserAdmin',page=p) }}">{{ p }}</a></li>
                {% else %}
                    <li ><a href="{{ url_for('UserAdmin',page=p) }}">{{ p }}</a></li>
                {% endif %}
        {% endfor %}


        {% else %}
            {%  if page_now-2 >0 %}
                <li><a href="{{ url_for('UserAdmin',page=page_now-2) }}">{{ page_now-2 }}</a></li>
            {% endif %}
            {% if  page_now-1 >0  %}
                <li><a href="{{ url_for('UserAdmin',page=page_now-1) }}">{{ page_now-1 }}</a></li>
            {% endif %}
                <li ><a style="background-color: darkgray;opacity: 0.7;color: black" href="{{ url_for('UserAdmin',page=page_now) }}">{{ page_now }}</a></li>
            {% if (page_count-page_now) >1  %}
                <li><a href="{{ url_for('UserAdmin',page=page_now+1) }}">{{ page_now+1 }}</a></li>
            {% endif %}
            {% if (page_count - page_now) >2 %}
                <li><a href="{{ url_for('UserAdmin',page=page_now+1) }}">{{ page_now+2 }}</a></li>
            {% endif %}
    {% endif %}

{#下一頁#}
    {%  if pagination.has_next  %}
        <li><a href="{{ url_for('UserAdmin',page=pagination.next_num) }}">&raquo;</a></li>
    {% endif %}

    <li><span style="color: black">頁數 ( {{ page_now }}/{{ page_count }} )</span></li>
</ul>


效果展現:

wKiom1gOOurSf9olAAAK6xH4iUE659.png

wKiom1gOOs-z9QPuAAAK6xH4iUE840.pngwKioL1gOOs-TWAuWAAAH7jdeSnQ274.png


常見的數據類型與配置



類型名稱 python類型 描述
Integer int 常規×××,一般爲32位
SmallInteger int 短×××,一般爲16位
BigInteger int或long 精度不受限×××
Float float 浮點數
Numeric decimal.Decimal 定點數
String str 可變長度字符串
Text str 可變長度字符串,適合大量文本
Unicode unicode

可變長度Unicode字符串

Boolean bool 布爾型
TIMESTAMP    timestamp          日期加時間類型
Date datetime.date 日期類型
Time datetime.time 時間類型
Interval datetime.timedelta 時間間隔
Enum str 字符列表
PickleType 任意Python對象 自動Pickle序列化
LargeBinary str 二進制

常見的SQLALCHEMY列選項

可選參數 描述
primary_key 若是設置爲True,則爲該列表的主鍵
unique 若是設置爲True,該列不容許相同值
index 若是設置爲True,爲該列建立索引,查詢效率會更高
nullable 若是設置爲True,該列容許爲空。若是設置爲False,該列不容許空值
default 定義該列的默認值

關係選項:

常見的SQLALCHEMY列類型.配置選項和關係選項

相關文章
相關標籤/搜索