flask項目結構(四)使用sqlalchemy和alembic


簡介

其實我不是啥正經人,錯了,不是啥正經程序員,所能想到的估計也就碼農一級吧,高級程序員,搞什么算法,什么人工智能,大數據計算…………離我還太遙遠。

但是這並不妨礙我繼續學習,繼續寫垃圾小程序。

反正我做的小程序,也就是把人從重復的勞動中解脫出來。用電腦代替人腦記憶那些枯燥的繁瑣的數據。用電腦來查詢記憶的數據。人腦的神經網絡是比計算機查找的快。隨便吧,還搞不到那個層次。先用電腦記錄查詢吧。

雖然python學習中已經學習了讀寫文件,在文件中查找,不過那都面向少量數據,更別提什么大數據了。幾萬行數據,你試試,搞起來累死了。新武器,數據庫。

數據庫:

抄吧
本詞條由“科普中國”百科科學詞條編寫與應用工作項目 審核 。
數據庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫,它產生於距今六十多年前,隨着信息技術和市場的發展,特別是二十世紀九十年代以后,數據管理不再僅僅是存儲和管理數據,而轉變成用戶所需要的各種數據管理的方式。數據庫有很多種類型,從最簡單的存儲有各種數據的表格到能夠進行海量數據存儲的大型數據庫系統都在各個方面得到了廣泛的應用。
在信息化社會,充分有效地管理和利用各類信息資源,是進行科學研究和決策管理的前提條件。數據庫技術是管理信息系統、辦公自動化系統、決策支持系統等各類信息系統的核心部分,是進行科學研究和決策管理的重要技術手段。

就是存數據,查數據,改數據…………的工具集合。

ORM:

繼續抄

對象關系映射(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程序技術,用於實現面向對象編程語言里不同類型系統的數據之間的轉換。

也就是不用你管數據庫怎么樣操作,怎么處理了,把數據庫變成了你程序當中的對象,你就像操作對象一樣來操作數據庫。降低了程序員的學習成本,你不需要額外再去學數據庫了。簡單學習一下數據庫對象的操作就可以使用數據庫了。

sqlalchemy:

還得抄

SQLAlchemy是Python編程語言下的一款開源軟件。提供了SQL工具包及對象關系映射(ORM)工具,使用MIT許可證發行。
SQLAlchemy“采用簡單的Python語言,為高效和高性能的數據庫訪問設計,實現了完整的企業級持久模型”。SQLAlchemy的理念是,SQL數據庫的量級和性能重要於對象集合;而對象集合的抽象又重要於表和行。因此,SQLAlchmey采用了類似於Java里Hibernate的數據映射模型,而不是其他ORM框架采用的Active Record模型。不過,Elixir和declarative等可選插件可以讓用戶使用聲明語法。

python中最出名的,最好用的,最…………反正python中,涉及數據庫的,我都用它了。

alembic:

不抄我怎么解釋

通常我們會將我們的代碼放入到某個VCS(版本控制系統)中,進行可追溯的版本管理。一個項目除了代碼,通常還會有一個數據庫,這個數據庫可能會隨着項目的演進發生變化,甚至需要可以回滾到過去的某個狀態,於是一些工具將數據庫的版本化也納入了管理。

Alembic 是 Sqlalchemy 的作者實現的一個數據庫版本化管理工具,它可以對基於Sqlalchemy的Model與數據庫之間的歷史關系進行版本化的維護。

隨着軟件的開發,功能的增加,方向的調整,數據庫的結構也會跟着變化,那么數據庫結構怎么管理呢?手動管理,實在不是程序員的辦法,alembic就是為了自動化處理數據庫結構的工具。會隨着程序中對數據庫對象的定義,半自動的修改你的數據庫結構。

一:安裝依賴

在python項目的虛擬環境中安裝sqlalchemy  alembic 和 MySQL-connector-python

二:創建數據庫連接

在項目根目錄增加文件config.py,項目配置文件。

本例只寫入了數據庫配置。以后cookie,session,加密的鹽,都寫這里吧。

config.py

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('mysql+mysqlconnector://plan:plan@mysql/plan', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()

這個配置文件使用了MySQL-connector-python庫連接第一篇文章寫的mariadb數據庫。

連接參數是'mysql+mysqlconnector://plan:plan@mysql/plan'

三:創建models

在項目根目錄創建目錄models,並在其中創建models.py文件。

models目錄是模型主目錄,公共部分模型,都放這里。

models.py就是模型了。

在app/app01目錄下創建app01_models.py,app01的私有models,就定義在這里了。

結構如下:

.
├── app
│   ├── alembic.ini
│   ├── app
│   │   ├── app01
│   │   │   ├── app01_models.py #新加,app01的私有models
│   │   │   └── views.py
│   │   ├── app02
│   │   │   └── views.py
│   │   └── main
│   │       └── views.py
│   ├── build_requirements.py
│   ├── config.py
│   ├── main.py
│   ├── migrate
│   │   ├── env.py
│   │   ├── README
│   │   ├── script.py.mako
│   │   └── versions
│   ├── models #新加目錄 │   │   └── models.py #公共models
│   └── requirements.txt
├── dockerfile
├── list.txt
└── rebuild.sh

/models/models.py

from config import Base
from sqlalchemy import Column, Integer, String


class User(Base):
    __tablename__ = 'public'
    id = Column(Integer, primary_key=True)
    public_name = Column(String(50))
    public_email = Column(String(120))
    
    def __init__(self, name=None, email=None):
        self.public_name = name
        self.public_email = email
    
    def __repr__(self):
        return '<User %r>' % (self.public_name)

/app/app01/app01_models.py

from config import Base
from sqlalchemy import Column, Integer, String


class app01(Base):
    __tablename__ = 'private'
    id = Column(Integer, primary_key=True)
    private_name = Column(String(50))
    private_email = Column(String(120))
    
    def __init__(self, name=None, email=None):
        self.private_name = name
        self.private_email = email
    
    def __repr__(self):
        return '<User %r>' % (self.private_name)

四:創建alembic擴展工具

在pycharm中用擴展工具來構建alembic的3條命令。

alembic init migrate                           創建alembic目錄結構

alembic revision --autogenerate       生成alembic升級腳本

alembic upgrade head                     升級數據庫結構到最新版

 

Program:$PyInterpreterDirectory$\alembic.exe這行比較長,抓圖看不清

五:創建alembic目錄結構

用剛才配置的擴展工具執行 init也可以。

直接執行命令  alembic init migrate 也可以。

會在項目目錄下生成一個目錄  migrage  一個配置文件 alembic.ini

生成結果如下:

.
├── app
│   ├── alembic.ini #自動增加文件,需配置
│   ├── app
│   │   ├── app01
│   │   │   ├── app01_models.py
│   │   │   └── views.py
│   │   ├── app02
│   │   │   └── views.py
│   │   └── main
│   │       └── views.py
│   ├── build_requirements.py
│   ├── config.py
│   ├── main.py
│   ├── migrate #自動增加目錄 │   │   ├── env.py #需修改
│   │   ├── README
│   │   ├── script.py.mako
│   │   └── versions
│   └── requirements.txt
├── dockerfile
├── list.txt
└── rebuild.sh

六:配置alembic

上一節已經標明了,需要修改配置的有兩個文件。

alembic.ini,其中配置數據庫連接參數。

修改這行:

sqlalchemy.url = driver://user:pass@localhost/dbname

改為我們的數據連接參數:

sqlalchemy.url = mysql+mysqlconnector://plan:plan@mysql/plan

env.py,其中配置models。

修改這行:

target_metadata = None

改為:

import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../")
from models import models
target_metadata = models.Base.metadata

其實我也不是很明白,大概就是引入路徑的問題,所以加了sys.path.append

七:生成升級腳本並升級數據庫

alembic revision --autogenerate       生成alembic升級腳本

alembic upgrade head                     升級數據庫結構到最新版

執行這兩個命令,或用擴展工具的圖形菜單。

八:檢查數據庫結構

跟隨第一張最后一節的測試。

點開數據庫,就能看到有表了。

如下:

哈哈,兩個對象結構,怎么只有一個public,private不見了。

專門留下來,沒創建。

alembic_version,是alembic自動創建,用來控制版本的,不要動就好了。

九:數據庫版本控制

來,改一下alembic配置models的地方。

import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../")
from models import models
from app.app01 import app01_models  #此行增加
target_metadata = models.Base.metadata

由於對象public和private都是由Base派生的,所以,只要target_metadata = models.Base.metadata,一遍就可以了。

部分教程中寫的是target_metadata = [models.Base.metadata,app01_models.Base.metadata],不知道怎么用。

可能是連接多數據庫時候用的。以后需要分庫的時候再說吧。看不懂的請忽略。

再來一遍生成版本控制腳本和升級數據庫結構。

private也出來了。

這就是自動化的數據庫結構版本控制。

十:結合docker

看這個鏡像作者的使用說明:

Custom /app/prestart.sh

If you need to run anything before starting the app, you can add a file prestart.sh to the directory /app. The image will automatically detect and run it before starting everything.

For example, if you want to add Alembic SQL migrations (with SQLALchemy), you could create a ./app/prestart.sh file in your code directory (that will be copied by your Dockerfile) with:

#! /usr/bin/env bash # Let the DB start sleep 10; # Run migrations alembic upgrade head

and it would wait 10 seconds to give the database some time to start and then run that alembic command.

If you need to run a Python script before starting the app, you could make the /app/prestart.sh file run your Python script, with something like:

#! /usr/bin/env bash # Run custom Python script before starting python /app/my_custom_prestart_script.y

Note: The image uses source to run the script, so for example, environment variables would persist. If you don't understand the previous sentence, you probably don't need it.

你可以在app啟動前,執行一些命令,那么正好,我們可以執行數據庫版本升級。

在app目錄下,創建prestart.sh

#! /usr/bin/env bash
# Let the DB start
sleep 10;
# Run migrations
alembic upgrade head

好了,隨便改改你的數據庫結構。只生成一下升級腳本,不用執行到服務器。

重建鏡像,它在啟動的時候就會自動幫你升級數據庫版本到最新版本了。

我使用這個是因為,我服務器5點自動重啟,然后就連不上數據庫了。重啟Flask這個鏡像,一切正常,手動重啟服務器,居然也都沒事。

這個升級數據庫腳本,正好在啟動APP前sleep 10秒。誰知道是不是因為啟動容器的順序的關系呢?這里sleep 10秒,也可以避免這個問題。

該文件請在linux下創建。

或者我寫進dockerfile。

FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7
MAINTAINER jackadam<jackadam@sina.com>
#變更源
# 安裝包源切到中科大, 國內訪問加速
RUN { \
        echo 'http://mirrors.ustc.edu.cn/alpine/v3.7/main'; \
        echo 'http://mirrors.ustc.edu.cn/alpine/v3.7/community'; \
        echo 'http://mirrors.ustc.edu.cn/alpine/edge/main'; \
        echo 'http://mirrors.ustc.edu.cn/alpine/edge/community'; \
        echo 'http://mirrors.ustc.edu.cn/alpine/edge/testing'; \
    } > /etc/apk/repositories && \

# 設置默認時區為亞洲/上海 (沒有北京可選)
        apk add --no-cache --upgrade apk-tools  && \
    apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone && \
    apk del tzdata

#升級pip
RUN  pip3 install --upgrade pip

#復制依賴包列表
COPY ./app/requirements.txt /app/requirements.txt

#安裝依賴包
RUN  pip3 install  -i https://pypi.doubanio.com/simple -r /app/requirements.txt 

#創建prestart.sh
RUN { \
        echo '#! /usr/bin/env bash'; \
        echo '# Let the DB start'; \
        echo 'sleep 10;'; \
        echo '# Run migrations'; \
        echo 'alembic upgrade head'; \
    } > /app/prestart.sh

#復制flask源碼
COPY ./app /app

 

 

結語

到此,我們已經創建了數據庫,新建flask項目,配置同步到服務器,服務器自動更新docker鏡像,用sqlalchemy連接數據庫,用alembic控制數據庫版本。

那么程序的版本怎么控制?用git啊。寫不寫git呢?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM