flask tutorial - RLidea/dev.docs GitHub Wiki

Flask ์‹œ์ž‘ํ•˜๊ธฐ

Flask ๋ฅผ ํ•™์Šตํ•˜๋ฉด์„œ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋กํ•จ.

Initialize

python, pip, brew ๋“ฑ์ด ์ด๋ฏธ ์„ค์น˜๋œ ์ƒํ™ฉ์—์„œ ์‹œ์ž‘.

1. ํ™˜๊ฒฝ ์„ค์ •

1-1. venv

pip๊ฐ€ ํŒจํ‚ค์ง€๋ฅผ global๊ณผ local๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ์„ค์น˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ์ ํŠธ๊ฐ„ ํ™˜๊ฒฝ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด virtualenv๊ฐ€ ํ•„์š”.
direnv๊ฐ€ ์ข€ ๋” ํŽธ๋ฆฌํ•˜๋‚˜ ์‚ฌ์šฉ๋ฒ•์ด ๊ฐ„๋‹จํ•˜์—ฌ ๊ธฐ๋ก์„ ๋‚จ๊ฒจ๋‘”๋‹ค.

์„ค์น˜

$ pip3 install virtualenv

venv ์ƒ์„ฑ

๋จผ์ € ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ด์„ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ์—์„œ venv ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์•„๋ž˜ ๋ช…๋ น์–ด์—์„œ venv ์•ž์— .์ด ๋ถ™์€ ๊ฑด ๋””๋ ‰ํ† ๋ฆฌ ์ด๋ฆ„ ์•ž์— .์„ ๋ถ™์—ฌ์„œ ์ˆจ๊น€ ํด๋”๋กœ ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. ์ €๊ธฐ์„œ ํ”„๋กœ์ ํŠธ ๋ช…์œผ๋กœ ์“ฐ๋Š” ์‚ฌ๋žŒ๋“ค๋„ ์žˆ๋˜๋ฐ ์ทจํ–ฅ์ธ ๊ฒƒ ๊ฐ™๋‹ค.

$ mkdir flask-demo
$ cs flask-demo
$ virtualenv .venv
$ virtualenv --version  # ์„ค์น˜ ํ™•์ธ

# ๋งŒ์•ฝ ํŒŒ์ด์ฌ์˜ ๋ฒ„์ „์„ ๊ณ ์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•œ๋‹ค. 
# ํ•ด๋‹น ๋ฒ„์ „์ด ๋กœ์ปฌ์— ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ๋งŒ ์„ค์ • ๊ฐ€๋Šฅํ•œ ๋“ฏ.
$ virtualenv -p python3.7 .venv

์‚ฌ์šฉ๋ฒ•

$ source .venv/bin/activate  # venv ํ™˜๊ฒฝ ์‹คํ–‰
$ deactivate  # ์ข…๋ฃŒ

์ •๋ง๋กœ ๋งค๋ฒˆ ์ผœ์ค˜์•ผํ•œ๋‹ค. ์ด๋ฅผ ํ”ผํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด direnv ์“ฐ๋Š”๊ฒŒ ๊ฐ€์žฅ ํŽธ๋ฆฌํ•œ ๋“ฏ.

1-2. direnv

direnv๋ฅผ ์ด์šฉํ•ด ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๋ฉด ์ข€ ๋” ๋ช…์‹œ์ ์œผ๋กœ ๋ฒ„์ „์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฌด์—‡๋ณด๋‹ค npm์ด๋‚˜ bundle์ฒ˜๋Ÿผ ๋””๋ ‰ํ„ฐ๋ฆฌ๋งˆ๋‹ค ์ž๋™์ ์œผ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, active, deactive ๋”ฐ์œ„๋ฅผ ์•ˆ ์จ๋„ ๋œ๋‹ค!

pyenv๋Š” ํŒŒ์ด์ฌ์˜ ๋ฒ„์ „ ๊ด€๋ฆฌ ์šฉ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  virtualenv๋Š” ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์„ ๊ด€๋ฆฌํ•˜๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

$ brew install pyenv
$ brew install direnv

pyenv๋Š” ~/.pyenv์•„๋ž˜์— ํŒŒ์ด์ฌ์„ ๋ฒ„์ „๋ณ„๋กœ ์„ค์น˜ํ•œ๋‹ค.

$ pyenv install 3.7.4  # python ์„ค์น˜
$ ~/.pyenv/versions/3.7.4/bin/pip install virtualenv  # ํ•ด๋‹น ๋ฒ„์ „์˜ python ํ™˜๊ฒฝ์— venv ์„ค์น˜

์…ธ ํ™˜๊ฒฝ์— ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

# zsh ์˜ ๊ฒฝ์šฐ
$ echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc

# bash ์˜ ๊ฒฝ์šฐ
$ echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

~/.direnvrc ์— ๋‹ค์Œ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•œ๋‹ค.

# See https://github.com/direnv/direnv/wiki/Python#-pyenv

use_python() {
  local python_root=$HOME/.pyenv/versions/$1
  load_prefix "$python_root"
  layout_python "$python_root/bin/python"
}

์ด์ œ direnv๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋กœ ๊ฐ€์„œ .envrc๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋‹ค์Œ์„ ์ž…๋ ฅํ•œ๋‹ค.

use python 3.7.4

์œ„์˜ ์„ค์ •์„ ํ—ˆ์šฉํ•ด์ค€๋‹ค.

$ direnv allow 

์ด์ œ .direnv๋ผ๋Š” ํด๋”๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์„ ๊ฒƒ์ด๋‹ค. ์ด๋Š” .venv์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•˜๊ณ , activate์‹œํ‚ค์ง€ ์•Š์•„๋„ ํ™˜๊ฒฝ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

2. Install Flask

ํ”Œ๋ผ์Šคํฌ๋ฅผ ์ด์šฉํ•œ REST API server ๊ฐœ๋ฐœ์— flask-restful๋‚˜ flask-restful-plus๋ผ๋Š” ํŒจํ‚ค์ง€๋„ ์žˆ๋Š” ๋ชจ์–‘์ธ๋ฐ, ์ด๋ฒˆ์—” ์™ ๋งŒํ•˜๋ฉด ํ”Œ๋ผ์Šคํฌ์˜ ๊ธฐ๋ณธ๊ธฐ๋ฅผ ์ตํžˆ๊ธฐ ์œ„ํ•ด ์•ˆ ์จ๋„ ๋  ๊ฑฐ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ตœ๋Œ€ํ•œ ์•ˆ ์“ฐ๊ณ  ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

Install

$ pip3 install flask

์ „ํ†ต์ ์ธ Hello World ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด Flask๊ฐ€ ์ž˜ ์„ค์น˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณธ๋‹ค.

vi app.py

from flask import Flask

app = Flask(__name__)


@app.route('/')  # decorator ๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ… ๊ฒฝ๋กœ๋ฅผ ์ง€์ •
def hello_world():
    return 'Hello, World!'


@app.route('/user/<user_id>')  # ๊ฐ€๋ณ€๋˜๋Š” URI ๋Š” <>๋ฅผ ์ด์šฉํ•ด ํ‘œํ˜„ํ•œ๋‹ค.
def user(user_id):
    return 'Hello, %s' % user_id


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

์‹คํ–‰

$ python3 app.py

http://127.0.0.1:5000/ ์—์„œ Hello World!๊ฐ€ ์ถœ๋ ฅ๋˜๋ฉด ์ž˜ ๋œ ๊ฒƒ์ด๋‹ค.

3. Manage Enviroments

Manage Packages

npm ์ฒ˜๋Ÿผ ์„ค์น˜๋œ ํŒจํ‚ค์ง€ ๋“ค์˜ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ๊ด€๋ฆฌ ํ•ด๋ณด์ž. requirements.txt๋กœ ํŒจํ‚ค์ง€๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ฑฐ์˜ ํ‘œ์ค€์ด๋ผ๊ณ  ํ•œ๋‹ค.

$ pip3 freeze > requirements.txt

ํ•ด๋‹น ํŒจํ‚ค์ง€ ๋“ค์„ ์„ค์น˜ํ•˜๋ ค๋ฉด

pip3 install -r requirements.txt

์œ„์™€ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํ˜‘์—… ์‹œ ํŒจํ‚ค์ง€๊ฐ€ ์„œ๋กœ ์•ˆ ๋งž๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ท€์ฐฎ์œผ๋‹ˆ shell script๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•˜์ž.

vi install-packages.sh
#!/bin/bash
pip3 install -r requirements.txt
pip3 freeze > requirements.txt

์ด์ œ source ./install-packages.sh ๋กœ ํŒจํ‚ค์ง€ ์„ค์น˜ ๋ฐ ๋ชฉ์ฐจ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

4. Project Structure

ํ”„๋กœ์ ํŠธ์˜ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž. ๋ˆ„๊ฐ€ ์ด๋ ‡๊ฒŒ ํ•˜๊ธธ๋ž˜ ์ผ๋‹จ ๋”ฐ๋ผํ•ด ๋ด„.

app/
โ”œ main/
โ”‚ โ”œ controllers/
โ”‚ โ”‚ โ”” __init__.py
โ”‚ โ”œ models/
โ”‚ โ”‚ โ”” __init__.py
โ”‚ โ”” __init__.py
โ”” test/
environments/
โ”œ requirements
โ”œ install-packages.sh
โ”” init.py
run.py

run.py

# Start script
from app.main import create_app


app = create_app()

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

app/main/__init__.py

from flask import Flask
    
    
def create_app():
    app = Flask(__name__)

    @app.route('/')  # decorator ๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ… ๊ฒฝ๋กœ๋ฅผ ์ง€์ •
    def hello_world():
        return 'Hello, World!'
    return app

5. Config & .env

config๊ฐ’๋“ค์„ app์ด ๋ฐ›์•„ ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•˜์ž. ์•ˆ์ „ํ•˜๊ฒŒ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด dotenv๋„ ์“ฐ์ž.

# https://pypi.org/project/python-dotenv
$ pip3 install -U python-dotenv # ์„ค์น˜

.env๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋•Œ ์‹ค์ œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ„ ํŒŒ์ผ์€ ์ปค๋ฐ‹ ํ•˜์ง€ ์•Š๊ณ , ๋™์ผํ•œ ํฌ๋ฉง์— ํŽ˜์ดํฌ๊ฐ’๋งŒ ๋“ค์–ด๊ฐ„ .env-example๊ฐ™์€ ํŒŒ์ผ์„ ์ปค๋ฐ‹ ํ•˜์—ฌ ์ƒํ™ฉ์— ๋งž๊ฒŒ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

ENV=development # development or production
    
HOST=0.0.0.0
PORT=5001
DEBUG=True
TESTING=False
MYSQL_DATABASE=homestead
MYSQL_USER=homestead
MYSQL_ROOT_PASSWORD=secret
MYSQL_PASSWORD=secret
MYSQL_PORT=3306
MYSQL_HOSTNAME=localhost

TEST_HOST=0.0.0.0
TEST_PORT=5000
TEST_DEBUG=False
TEST_TESTING=True
TEST_MYSQL_DATABASE=homestead
TEST_MYSQL_USER=homestead
TEST_MYSQL_PASSWORD=secret
TEST_MYSQL_ROOT_PASSWORD=secret
TEST_MYSQL_PORT=3306
TEST_MYSQL_HOSTNAME=localhost

PRO_HOST=0.0.0.0
PRO_PORT=5000
PRO_DEBUG=False
PRO_TESTING=False
PRO_MYSQL_DATABASE=homestead
PRO_MYSQL_USER=homestead
PRO_MYSQL_PASSWORD=secret
PRO_MYSQL_ROOT_PASSWORD=secret
PRO_MYSQL_PORT=3306
PRO_MYSQL_HOSTNAME=localhost

config.py ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

import os
from os.path import join, dirname
from dotenv import load_dotenv


def get_env(key):
    dotenv_path = join(dirname(__file__), '.env')
    load_dotenv(dotenv_path)

    return os.getenv(key)


def config(key):
    if get_env('ENV') == 'development':
        return get_env(key)
    elif get_env('ENV') == 'test':
        return get_env('TEST' + key)
    elif get_env('ENV') == 'production':
        return get_env('PRO' + key)


# Server Configuration
ENV = get_env('ENV')
DEBUG = config('DEBUG')
TESTING = config('TESTING')

HOST = config('HOST')
PORT = config('PORT')

# Database Configuration
MYSQL_DATABASE = config('MYSQL_DATABASE')
MYSQL_USER = config('MYSQL_USER')
MYSQL_ROOT_PASSWORD = config('MYSQL_ROOT_PASSWORD')
MYSQL_PASSWORD = config('MYSQL_PASSWORD')
MYSQL_PORT = config('MYSQL_PORT')
MYSQL_HOSTNAME = config('MYSQL_HOSTNAME')

app/main/__init__.py์™€ run.py๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.

app/main/__init__.py

from flask import Flask
    
    
def create_app(override=None):
    app = Flask(__name__)

    # Initialize config (config.py)
    app.config.from_object('config')
    if override:
        app.config.update(override)

    @app.route('/')  # decorator ๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ… ๊ฒฝ๋กœ๋ฅผ ์ง€์ •
    def hello_world():
        return 'Hello, World!'
    return app

run.py

# Start script
from app.main import create_app


app = create_app()

if __name__ == '__main__':
    app.run(
        host=app.config['HOST'],
        port=app.config['PORT'],
        debug=app.config['DEBUG']
    )

6. ORM

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ๋‚ด์šฉ์„ ORM์œผ๋กœ ์ฒ˜๋ฆฌ ํ•ด ๋ณด์ž. ๋“ฃ์ž ํ•˜๋‹ˆ migration์€ Alembic ์„ ๋งŽ์ด ์“ฐ๊ณ  ๋ชจ๋ธ ๊ด€๋ฆฌ๋Š” SQLAlchemy๋ฅผ ๋งŽ์ด ์“ด๋‹ค. ์ด๋•Œ, ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๋“ฑ์˜ ๊ธฐ๋Šฅ์€ SQLAlchemy์—๊ฒŒ ์žˆ๊ณ , migration script๋“ค์„ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ๋ถ€๋ถ„์ด Alembic์ด๋‹ค.
์ผ๋‹จ mysql ๊ธฐ์ค€์œผ๋กœ. migration ๋ถ€ํ„ฐ.

Migration with Alembic

# https://alembic.sqlalchemy.org/en/latest/
$ pip3 install alembic # ์„ค์น˜
$ alembic init database # ์ดˆ๊ธฐํ™”. ์ด ๋•Œ init ๋’ค์˜ database ๋Š” ์ž„์˜๋กœ ์ •ํ•œ ํด๋” ๋ช…์ด๋‹ค.
$ pip3 install SQLAlchemy-Utils # migration ๋“ฑ์—์„œ ํŒŒ์ผ ํƒ€์ž…์„ ๋””ํ…Œ์ผํ•˜๊ฒŒ ์ •ํ•  ๋•Œ ์”€

Alembic๋ฅผ ์„ค์น˜ํ•˜๋ฉด SQLAlchemy๊ฐ€ ๊ฐ™์ด ์„ค์น˜๋œ๋‹ค. (pip3 freeze๋กœ ํ™•์ธ)

์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€๋œ๋‹ค.

database/
โ”œ versions/
โ”œ env.py
โ”œ README
โ”” script.py.mako
alembic.ini

์„ค์น˜๋ฅผ ํ–ˆ์œผ๋‹ˆ, DB์™€ ์—ฐ๊ฒฐํ•ด ๋ณด์ž.

์›๋ž˜๋Š” alembic.ini์˜ sqlalchemy.url๊ฐ’์„ ์ˆ˜์ •ํ•ด์„œ ์ ‘์† ํ•˜๋Š”๊ฒŒ ๊ธฐ๋ณธ์ด๋‹ค.

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

๊ฐ€ ๋“ค์–ด์žˆ๋Š”๋ฐ, ์ด๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์จ์•ผ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

sqlalchemy.url = mysql+pymysql://username:password@localhost/dbname

ํ•˜์ง€๋งŒ .env๋กœ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•˜๋Š” ์ž…์žฅ์—์„œ ๋งˆ์Œ์— ์•ˆ ๋“ค๊ณ  ๋ณด์•ˆ์ƒ์œผ๋กœ ์ข‹์ง€๋‹ˆ ์•Š์œผ๋‹ˆ env.py๋ฅผ ์ˆ˜์ • ํ•˜๊ธฐ๋กœ ํ•œ๋‹ค.

database/connection.py๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ ๋‹ค.

from sqlalchemy import create_engine
from config import MYSQL_USER, MYSQL_PASSWORD, MYSQL_HOSTNAME, MYSQL_DATABASE


def database_url():
    return "mysql+pymysql://%s:%s@%s/%s" % (
        MYSQL_USER,
        MYSQL_PASSWORD,
        MYSQL_HOSTNAME,
        MYSQL_DATABASE,
    )


engine = create_engine(database_url())

๊ทธ๋ฆฌ๊ณ  env.py ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค. ์ค‘์š”ํ•œ ๊ฑด run_migrations_online()ํ•จ์ˆ˜ ๋‚ด์šฉ์ด ๋ณ€๊ฒฝ ๋˜์—ˆ๋‹ค๋Š” ์ ์ด๋‹ค.

from logging.config import fileConfig
from sqlalchemy import create_engine
from alembic import context
from os.path import abspath, dirname
from sys import path
path.append(dirname(dirname(abspath(__file__))))  # ์ด๊ฒŒ ์—†์œผ๋‹ˆ database ํด๋”๋ฅผ ๋ชป ์ฐพ๋”๋ผ.



... ์ค‘๋žต ... 



def run_migrations_online():
    from database.connection import engine

    connectable = engine

    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )

        with context.begin_transaction():
            context.run_migrations()


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()

์ด์ œ DB์—ฐ๊ฒฐ ์„ค์ •๋„ ์™„๋ฃŒ๋˜์—ˆ๋‹ค.

Alembic์˜ ์‚ฌ์šฉ๋ฒ•์€ php์˜ Eloquent ๋‚˜ node.js์˜ Sequelize ๋“ฑ ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ ์“ฐ๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

$ alembic revision -m "๋ฉ”๋ชจ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ฉ์‹œ๋‹ค"  # ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์Šคํฌ๋ฆฝํŠธ ์ƒ์„ฑ
$ alembic upgrade head  # ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์Šคํฌ๋ฆฝํŠธ ์ ์šฉ

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด database/versions์— ์ฐจ๊ณก์ฐจ๊ณก ์Œ“์ธ๋‹ค.

ํ…Œ์ด๋ธ” ํ•˜๋‚˜ ์ƒ์„ฑ ํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ํ•˜๋‚˜ ๋“ค๋ฉด: ์•„๋ž˜ ๋ช…๋ น์–ด๋กœ migration script๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ๋‹ค.

$ alembic revision -m "create users table"

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์Šคํฌ๋ฆฝํŠธ์— ์›ํ•˜๋Š” ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

1f9b6bfff97e_create_users_table.py

"""create users table
    
Revision ID: 1f9b6bfff97e
Revises: 36d29f362525
Create Date: 2019-10-15 16:15:58.827570

"""
from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils as su

# revision identifiers, used by Alembic.
revision = '1f9b6bfff97e'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    op.create_table(
        'Users',
        sa.Column('id', su.types.uuid.UUIDType, nullable=False),
        sa.Column('username', sa.VARCHAR(length=100), nullable=False),
        sa.Column('password', sa.CHAR(length=41), nullable=False),
        sa.Column('name', sa.VARCHAR(length=30), nullable=False),
        sa.PrimaryKeyConstraint('id'),
        mysql_charset='utf8mb4',
        mysql_collate='utf8mb4_unicode_ci',
        mysql_engine='InnoDB',
        mysql_row_format='DYNAMIC'
    )
    pass


def downgrade():
    op.drop_table('Users')
    pass

์ด์ œ ์œ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ํ•œ๋‹ค.

$ alembic upgrade head
$ alembic downgrade -1 # ํ•œ ๋‹จ๊ณ„ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ

๋ณธ์ธ์˜ DB์— Usersํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋œ ๊ฒƒ์ด ํ™•์ธ๋œ๋‹ค๋ฉด ์„ฑ๊ณต ํ•œ ๊ฒƒ์ด๋‹ค.

Model Control with SQLAlchemy

...

(์ž‘์„ฑ์ค‘)

2019-10-24

โš ๏ธ **GitHub.com Fallback** โš ๏ธ