ORM (Object-Relational Mapping)
๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด๋ก ๋งคํํ๋ ๋ฐฉ๋ฒ
Flask-SQLAlchemy๋ Python ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ ๊ฐ์ ๋งคํ์ ์๋์ผ๋ก ์ฒ๋ฆฌ -> SQL ์ฟผ๋ฆฌ ์์ฑ ์์ด Python ๊ฐ์ฒด๋ฅผ ๋ค๋ฃจ๋ฏ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉ ๊ฐ๋ฅ
# ORM ์ค์น
$ pip install flask-migrate
ORM ๊ตฌ์ฑ
1. config.py
- .env ํ์ผ: ์ ํ๋ฆฌ์ผ์ด์
์ธ๋ถ์์ ํ๊ฒฝ ๋ณ์๋ฅผ ๊ด๋ฆฌํ๋ ํ์ผ
- ๋น๋ฐ๋ฒํธ, API ํค, ๋ฐ์ดํฐ๋ฒ ์ด์ค URI์ ๊ฐ์ ๋ฏผ๊ฐํ ์ค์ ๊ฐ๋ค์ด ํฌํจ
- SQLALCHEMY_DATABASE_URI: ๋ฐ์ดํฐ๋ฒ ์ด์ค URI๋ฅผ ์ค์
- SQLALCHEMY_TRACK_MODIFICATIONS: False๋ก ์ค์ ํ์ฌ Flask๊ฐ ๊ฐ์ฒด ๋ณ๊ฒฝ ์ถ์ ์ ํ์ง ์๊ฒ ํ๋ค.
import os
BASE_DIR = os.path.dirname(__file__)
SQLALCHEMY_DATABASE_URI = 'sqlite:///{}'.format(os.path.join(BASE_DIR, 'test.db'))
SQLALCHEMY_TRACK_MODIFICATIONS = False
2. app.py
- create_app(): Flask ์ ํ๋ฆฌ์ผ์ด์
์ ํฉํ ๋ฆฌ ํจํด์ผ๋ก ์์ฑ
- db.init_app(app): Flask-SQLAlchemy์ db ๊ฐ์ฒด๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฐ๊ฒฐ
- migrate.init_app(app, db): ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง์ด๊ทธ๋ ์ด์ ์ ์ฒ๋ฆฌํ๋ Flask-Migrate์ ์ด๊ธฐํ ์ฝ๋
from flask import Flask, jsonify
from models import db, Product, User
import config
app = Flask(__name__)
app.config.from_object(config)
# ORM ์ด๊ธฐํ
db.init_app(app)
@app.route('/add_product')
def add_product():
# ์๋ก์ด Product ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ DB์ ์ถ๊ฐ
new_product = Product(name="Sample Product", price=19.99)
db.session.add(new_product)
db.session.commit()
return "Product added!"
@app.route('/get_products')
def get_products():
# DB์์ ๋ชจ๋ Product ์กฐํ
products = Product.query.all()
return jsonify([product.to_dict() for product in products])
@app.route('/add_user')
def add_user():
# ์๋ก์ด User ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ DB์ ์ถ๊ฐ
new_user = User(username="sample_user", email="user@example.com")
db.session.add(new_user)
db.session.commit()
return "User added!"
@app.route('/get_users')
def get_users():
# DB์์ ๋ชจ๋ User ์กฐํ
users = User.query.all()
return jsonify([user.to_dict() for user in users])
if __name__ == '__main__':
app.run(debug=True)
3. models.py
- db.Model์ ์์๋ฐ์ ๊ฐ ํด๋์ค๋ SQLAlchemy ๋ชจ๋ธ์ด ๋๊ณ , ์ด ํด๋์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ๊ณผ ๋งคํ๋๋ค.
- ๊ฐ ๋ชจ๋ธ์๋ ์ปฌ๋ผ์ ์ ์
- ex) Product ๋ชจ๋ธ์ id, name, price ์ปฌ๋ผ / User ๋ชจ๋ธ์ id, username, email ์ปฌ๋ผ
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
price = db.Column(db.Float, nullable=False)
def to_dict(self):
return {"id": self.id, "name": self.name, "price": self.price}
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def to_dict(self):
return {"id": self.id, "username": self.username, "email": self.email}
4. ๋ง์ด๊ทธ๋ ์ด์
Flask, Django, FastAPI์์ ORM์ ์ฌ์ฉํ๋ ค๋ฉด ๋ง์ด๊ทธ๋ ์ด์ ์ ํด์ผ ํ๋ค.
๋ชจ๋ธ์ ์์ ํ๊ฑฐ๋ ๋ณ๊ฒฝํ ๋ ํด๋น ๋ณ๊ฒฝ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ํ๋ ค๋ฉด ๋ง์ด๊ทธ๋ ์ด์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ฅผ ์ ๋ฐ์ดํธ
- Flask: Flask-SQLAlchemy์ Flask-Migrate๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ ๋ณ๊ฒฝ ์ ๋ง์ด๊ทธ๋ ์ด์ ํ์
- Django: ๋ด์ฅ๋ makemigrations์ migrate ๋ช ๋ น์ด๋ก ์๋ ๋ง์ด๊ทธ๋ ์ด์
- FastAPI: SQLAlchemy์ Alembic์ ์ฌ์ฉํด ๋ชจ๋ธ ๋ณ๊ฒฝ ์ ๋ง์ด๊ทธ๋ ์ด์ ํ์
์ฆ, ORM์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ธ๊ณผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ฅผ ์ผ์น์ํค๊ธฐ ์ํด ๋ง์ด๊ทธ๋ ์ด์ ์ ํด์ผ ํ๋ค๋ ๊ฒ
๋ช ๋ น์ด
๋ช ๋ น์ด | ์ค๋ช |
flask db init | ๋ง์ด๊ทธ๋ ์ด์ ํ๊ฒฝ ์ด๊ธฐํ (์ฒ์ ํ ๋ฒ๋ง ์คํ) |
flask db migrate -m "๋ฉ์์ง" | ๋ชจ๋ธ ๋ณ๊ฒฝ ์ฌํญ์ ๋ง์ด๊ทธ๋ ์ด์ ํ์ผ๋ก ์์ฑ |
flask db upgrade | ๋ง์ด๊ทธ๋ ์ด์ ์ ์คํํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ต์ ์ํ๋ก ๋ง๋ ๋ค. |
flask db downgrade | ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑ |
flask db history | ๋ง์ด๊ทธ๋ ์ด์ ๊ธฐ๋ก ํ์ธ |
flask db current | ํ์ฌ ๋ง์ด๊ทธ๋ ์ด์ ์ํ ํ์ธ |
flask db stamp head | ํ์ฌ DB ์ํ๋ฅผ ์ต์ ๋ง์ด๊ทธ๋ ์ด์ ์ผ๋ก ํ์ (์ค์ ์ ๊ทธ๋ ์ด๋๋ ์ ํจ) |
flask db init
flask db migrate -m "Initial migration"
flask db upgrade
์ ๋ฆฌํด๋ณด์
ORM ์ฌ์ฉ ํ๋ฆ
- ๋ชจ๋ธ ์ ์
- Product์ User์ ๋ชจ๋ธ์ ์ ์ํ์ฌ ๊ฐ ๊ฐ์ฒด๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ๊ณผ ์ด๋ป๊ฒ ๋งคํ๋๋์ง ์ค์
- ๊ฐ ๋ชจ๋ธ์ ํด๋์ค ์์ฑ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ปฌ๋ผ๊ณผ ๋์๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์
์ฌ์ฉ
- db.session.add()์ db.session.commit()์ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ถ๊ฐํ๊ณ ์ ์ฅ
- ex) ์ ์ ํ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ถ๊ฐํ๋ ค๋ฉด Product(name='์ ์ ํ', price=10.0)์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด db.session.add()๋ก ์ถ๊ฐํ ํ, db.session.commit()์ ํธ์ถํ์ฌ ์ ์ฅ
- db.session.add()์ db.session.commit()์ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ถ๊ฐํ๊ณ ์ ์ฅ
- ์ฟผ๋ฆฌ ์ํ
- Product.query.all() ๋๋ Product.query.filter_by(name='์ ํ ์ด๋ฆ')๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก SQLAlchemy์ ์ฟผ๋ฆฌ API๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ ์กฐํ
User๋ ๋ง์ฐฌ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก DB์ ์ ์ฅ๋๋ ๊ฒ์ ํ์ธ๊ฐ๋ฅ
๋ชจ๋ธ ๊ฐ์ ๊ด๊ณ ์ค์
์ด์ ํ ์ด๋ธ์ ์ฐ๊ฒฐํด๋ณด์
Product์ User ๋ชจ๋ธ์ ๊ธฐ๋ฐ์ผ๋ก Category๋ผ๋ ์๋ก์ด ๋ชจ๋ธ์ ๋ง๋ค์ด์ ๋ ๋ชจ๋ธ์ ์๋ก ์ฐ๊ฒฐ
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
price = db.Column(db.Float, nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False) # ์ธ๋ํค๋ก ์นดํ
๊ณ ๋ฆฌ์ ์ฐ๊ฒฐ๋จ
category = db.relationship('Category', backref=db.backref('products', lazy=True)) # ์ญ์ฐธ์กฐ ์ค์
def to_dict(self):
return {"id": self.id, "name": self.name, "price": self.price}
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False, unique=True)
def to_dict(self):
return {"id": self.id, "name": self.name}
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def to_dict(self):
return {"id": self.id, "username": self.username, "email": self.email}
- Product ๋ชจ๋ธ์ category_id๋ผ๋ ์ธ๋ ํค๋ฅผ ์ถ๊ฐํ์ฌ Category ๋ชจ๋ธ๊ณผ ์ฐ๊ฒฐ
- category = db.relationship('Category', backref=db.backref('products', lazy=True))๋ Product ๋ชจ๋ธ์์ Category ๋ชจ๋ธ์ ์ฐธ์กฐํ ์ ์๊ฒ ๋จ
- Category ๋ชจ๋ธ์์ products๋ฅผ ์ญ์ฐธ์กฐํ๋ฉด, ํน์ ์นดํ ๊ณ ๋ฆฌ์ ์ํ ๋ชจ๋ ์ ํ๋ค์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
from flask import Flask, jsonify
from models import db, Product, User, Category
import config
app = Flask(__name__)
app.config.from_object(config)
# ORM ์ด๊ธฐํ
db.init_app(app)
@app.route('/add_category')
def add_category():
# ์๋ก์ด Category ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ DB์ ์ถ๊ฐ
new_category = Category(name="Electronics")
db.session.add(new_category)
db.session.commit()
return "Category added!"
@app.route('/add_product')
def add_product():
# ์๋ก์ด Product ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ DB์ ์ถ๊ฐ
# ์ด๋ฏธ ์กด์ฌํ๋ Category ID๋ฅผ ํ ๋นํ์ฌ Product์ ์ฐ๊ฒฐ
category = Category.query.first() # ์ฒซ ๋ฒ์งธ ์นดํ
๊ณ ๋ฆฌ ๊ฐ์ ธ์ค๊ธฐ (์์๋ก)
new_product = Product(name="Laptop", price=999.99, category_id=category.id)
db.session.add(new_product)
db.session.commit()
return "Product added!"
@app.route('/get_categories')
def get_categories():
# DB์์ ๋ชจ๋ Category ์กฐํ
categories = Category.query.all()
return jsonify([category.to_dict() for category in categories])
@app.route('/get_products')
def get_products():
# DB์์ ๋ชจ๋ Product ์กฐํ
products = Product.query.all()
return jsonify([product.to_dict() for product in products])
@app.route('/get_products_by_category/<int:category_id>')
def get_products_by_category(category_id):
# ํน์ ์นดํ
๊ณ ๋ฆฌ์ ์ ํ๋ค ์กฐํ
category = Category.query.get_or_404(category_id)
products = category.products # ์ญ์ฐธ์กฐ๋ฅผ ํตํด ๊ด๋ จ๋ ์ ํ ์กฐํ
return jsonify([product.to_dict() for product in products])
@app.route('/add_user')
def add_user():
# ์๋ก์ด User ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ DB์ ์ถ๊ฐ
new_user = User(username="sample_user", email="user@example.com")
db.session.add(new_user)
db.session.commit()
return "User added!"
@app.route('/get_users')
def get_users():
# DB์์ ๋ชจ๋ User ์กฐํ
users = User.query.all()
return jsonify([user.to_dict() for user in users])
if __name__ == '__main__':
app.run(debug=True)
- add_category์ add_product๋ ์๋ก์ด ์นดํ
๊ณ ๋ฆฌ์ ์ ํ์ ์ถ๊ฐํ๋ ๋ผ์ฐํธ
- ์นดํ ๊ณ ๋ฆฌ๋ฅผ ๋จผ์ ์ถ๊ฐํ ํ, ํด๋น ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์ ํ์ ํ ๋นํ๋ ๋ฐฉ์
- get_categories๋ ๋ชจ๋ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์กฐํํ๋ ๋ผ์ฐํธ
- get_products_by_category๋ ํน์ ์นดํ
๊ณ ๋ฆฌ์ ์ํ ์ ํ๋ค์ ์กฐํํ๋ ๋ผ์ฐํธ
- category.products๋ฅผ ํตํด ํด๋น ์นดํ ๊ณ ๋ฆฌ์ ๋ชจ๋ ์ ํ์ ๊ฐ์ ธ์ค๊ฒ ๋จ
์๋ก์ด ๋ชจ๋ธ์ ์ถ๊ฐํ์ผ๋ฏ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง์ด๊ทธ๋ ์ด์ ์ ํตํด ํ ์ด๋ธ์ ์ ๋ฐ์ดํธํด์ผ ํ๋ค.
์ข ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ์ ์ง๊ณ ๋์ด๊ฐ์
Blueprint์ Route์ ์ฐจ์ด
- Route: Flask ์ ํ๋ฆฌ์ผ์ด์ ์ URL ๊ฒฝ๋ก์ ํจ์(ํธ๋ค๋ฌ)๋ฅผ ์ฐ๊ฒฐํ๋ ๊ธฐ๋ฅ
- Blueprint: ์ฌ๋ฌ ๋ผ์ฐํธ๋ฅผ ๊ทธ๋ฃนํํ ์ ์๋ ๋ฐฉ๋ฒ
- ํฐ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ผ์ฐํธ๋ฅผ ๋ถ๋ฆฌํ๊ณ ์ถ์ ๋ Blueprint๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ๋ชจ๋ํ
'๐ผ ๋ฐฑ์ค๋ > Flask' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Flask์์ ํ ํ๋ฆฟ ์ฌ์ฉํ๊ธฐ (0) | 2025.03.29 |
---|---|
Flask ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์กฐ์ ๋์ ์๋ฆฌ (0) | 2025.03.26 |