[flask] Do it ์ ํ ํฌ ํ๋ผ์คํฌ _ 2. ํ๋ก์ ํธ ๊ตฌ์กฐ ๋ฐ ๊ฐ๋ ์ดํด
- -
ํด๋น ์๋ฃ ๋ฐ ์ค์ต์ ๋ชจ๋ ์ํค๋ ์ค(์ ํ ํฌ ํ๋ผ์คํฌ) ๋ด์ฉ์ ์ฐธ๊ณ ํ ์์ฑํ ๊ฒ์ ๋๋ค.
* ์๋๋ ๊ฐ ํ์ผ์ด ์ด๋ ํ ๊ธฐ๋ฅ์ ํ๋์ง ๋ํ๋ธ ๊ฒ์ด๋ค. (์ถ์ฒ : ์ํค๋ ์ค)
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฒ๋ฆฌํ๋ models.py ํ์ผ
ํ์ด๋ณด ํ๋ก์ ํธ๋ ORM(object relational mapping)์ ์ง์ํ๋ ํ์ด์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๊ตฌ์ธ SQLAlchemy๋ฅผ ์ฌ์ฉํ๋ค. SQLAlchemy๋ ๋ชจ๋ธ ๊ธฐ๋ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฒ๋ฆฌํ๋ค. ์ง๊ธ์ ๋ชจ๋ธ ๊ธฐ๋ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฒ๋ฆฌํ๋ค๋ ๋ง์ด ์ดํด๋์ง ์๊ฒ ์ง๋ง, ์ดํ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด ์ ์ ์ ์์ ๊ฒ์ด๋ค. ์๋ฌดํผ ์ง๊ธ ์ฌ๋ฌ๋ถ์ด ์์์ผ ํ ๋ด์ฉ์ ํ์ด๋ณด ํ๋ก์ ํธ์๋ "๋ชจ๋ธ ํด๋์ค๋ค์ ์ ์ํ models.py ํ์ผ์ด ํ์ํ๋ค"๋ ๊ฒ์ด๋ค.
์๋ฒ๋ก ์ ์ก๋ ํผ์ ์ฒ๋ฆฌํ๋ forms.py ํ์ผ
ํ์ด๋ณด ํ๋ก์ ํธ๋ ์น ๋ธ๋ผ์ฐ์ ์์ ์๋ฒ๋ก ์ ์ก๋ ํผ์ ์ฒ๋ฆฌํ ๋ WTForms๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค. WTForms ์ญ์ ๋ชจ๋ธ ๊ธฐ๋ฐ์ผ๋ก ํผ์ ์ฒ๋ฆฌํ๋ค. ๊ทธ๋์ ํผ ํด๋์ค๋ฅผ ์ ์ํ forms.py ํ์ผ์ด ํ์ํ๋ค.
ํ๋ฉด์ ๊ตฌ์ฑํ๋ views ๋๋ ํฐ๋ฆฌ
pybo.py ํ์ผ์ ์์ฑํ๋ hello_pybo ํจ์์ ์ญํ ์ ํ๋ฉด ๊ตฌ์ฑ์ด์๋ค. views ๋๋ ํฐ๋ฆฌ์๋ ๋ฐ๋ก ์ด๋ฐ ํจ์๋ค๋ก ๊ตฌ์ฑ๋ ๋ทฐ ํ์ผ๋ค์ ์ ์ฅํ๋ค. ํ์ด๋ณด ํ๋ก์ ํธ์๋ ๊ธฐ๋ฅ์ ๋ฐ๋ผ main_views.py, question_views.py, answer_views.py ๋ฑ์ ๋ทฐ ํ์ผ์ ๋ง๋ค ๊ฒ์ด๋ค.
CSS, ์๋ฐ์คํฌ๋ฆฝํธ, ์ด๋ฏธ์ง ํ์ผ์ ์ ์ฅํ๋ static ๋๋ ํฐ๋ฆฌ
static ๋๋ ํฐ๋ฆฌ๋ ํ์ด๋ณด ํ๋ก์ ํธ์ ์คํ์ผ์ํธ(.css), ์๋ฐ์คํฌ๋ฆฝํธ(.js) ๊ทธ๋ฆฌ๊ณ ์ด๋ฏธ์ง ํ์ผ(.jpg, .png) ๋ฑ์ ์ ์ฅํ๋ค.
HTML ํ์ผ์ ์ ์ฅํ๋ templates ๋๋ ํฐ๋ฆฌ
templates ๋๋ ํฐ๋ฆฌ์๋ ํ์ด๋ณด์ ์ง๋ฌธ ๋ชฉ๋ก, ์ง๋ฌธ ์์ธ ๋ฑ์ HTML ํ์ผ์ ์ ์ฅํ๋ค. ํ์ด๋ณด ํ๋ก์ ํธ๋ question_list.html, question_detail.html๊ณผ ๊ฐ์ ํ ํ๋ฆฟ ํ์ผ์ ๋ง๋ค์ด ์ฌ์ฉํ ๊ฒ์ด๋ค.
ํ์ด๋ณด ํ๋ก์ ํธ๋ฅผ ์ค์ ํ๋ config.py ํ์ผ
config.py ํ์ผ์ ํ์ด๋ณด ํ๋ก์ ํธ์ ํ๊ฒฝ์ ์ค์ ํ๋ค. ํ์ด๋ณด ํ๋ก์ ํธ์ ํ๊ฒฝ๋ณ์, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฑ์ ์ค์ ์ ์ด ํ์ผ์ ์ ์ฅํ๋ค.
#ํ๋ผ์คํฌ ์ ํ๋ฆฌ์ผ์ด์ ํฉํ ๋ฆฌ
ํ๋ผ์คํฌ๋ app ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํด ์ฌ๋ฌ ๊ฐ์ง ์ค์ ์ ์งํํ๋ค. ๊ทธ๋ฐ๋ฐ ์ด์ ๊ฐ์ ๋ฐฉ์์ผ๋ก app ๊ฐ์ฒด๋ฅผ ์ ์ญ์ผ๋ก ์ฌ์ฉํ๋ฉด ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์ปค์ง์๋ก ๋ฌธ์ ๊ฐ ๋ฐ์ํ ํ๋ฅ ์ด ๋์์ง๋ค. ์ํ ์ฐธ์กฐ(circular import) ์ค๋ฅ๊ฐ ๋ํ์ ์ด๋ค.
์ํ ์ฐธ์กฐ๋ A ๋ชจ๋์ด B ๋ชจ๋์ ์ฐธ์กฐํ๊ณ B ๋ชจ๋์ด ๋ค์ A ๋ชจ๋์ ์ฐธ์กฐํ๋ ๊ฒฝ์ฐ๋ฅผ ๋งํ๋ค.
app ๊ฐ์ฒด๋ฅผ ์ ์ญ์ผ๋ก ์ฌ์ฉํ ๋ ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ์๋ฐฉํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น? ํ๋ผ์คํฌ ๊ณต์ ํํ์ด์ง์์๋ "์ ํ๋ฆฌ์ผ์ด์ ํฉํ ๋ฆฌ(application factory)๋ฅผ ์ฌ์ฉํ๋ผ"๊ณ ๊ถํ๋ค.
# pybo.py๋ฅผ __init__.py ํ์ผ๋ก ๋ณ๊ฒฝ
ํ๋ผ์คํฌ ๊ธฐ๋ณธ ์ฑ์ FLASK_APP=pybo๋ก ์ค์ ํ๋ฉด, ๊ธฐ์กด์ pybo๋ ํ๋ก์ ํธ ๋ฃจํธ์ ์๋ pybo.py ํ์ผ์ ๊ฐ๋ฆฌ์ผฐ์ง๋ง,
๋ ๋ค๋ฅด๊ฒ pybo ๋ชจ๋ ์ฆ pybo/__init__.py ํ์ผ์ ๊ฐ๋ฆฌํจ๋ค.
pybo.py ์ pybo/__init__.py๋ ๋์ผํ pybo ๋ชจ๋์ด๋ค.
๋ฐ๋ผ์ pybo.py ํ์ผ์ pybo/__init__.py ํ์ผ๋ก ๋ฐ๊พธ์ด๋ ์ค๋ฅ์์ด ์ ๋์ํ๋ค.
# ์ ํ๋ฆฌ์ผ์ด์ ํฉํ ๋ฆฌ
from flask import Flask
def create_app():
app = Flask(__name__)
@app.route('/')
def hello_pybo():
return 'string test'
return app
create_app ํจ์๊ฐ app ๊ฐ์ฒด๋ฅผ ์์ฑํด ๋ฐํํ๋๋ก ์ฝ๋๋ฅผ ์์ ํ๋ค. ์ด๋ app ๊ฐ์ฒด๊ฐ ํจ์ ์์์ ์ฌ์ฉ๋๋ฏ๋ก hello_pybo ํจ์๋ฅผ create_app ํจ์ ์์ ํฌํจํ๋ค. ๋ฐ๋ก ์ฌ๊ธฐ์ ์ฌ์ฉ๋ create_app ํจ์๊ฐ ๋ฐ๋ก ์ ํ๋ฆฌ์ผ์ด์ ํฉํ ๋ฆฌ๋ค.
ํจ์๋ช ์ผ๋ก create_app ๋์ ๋ค๋ฅธ ์ด๋ฆ์ ์ฌ์ฉํ๋ฉด ์ ์์ผ๋ก ๋์ํ์ง ์๋๋ค.
create_app์ ํ๋ผ์คํฌ ๋ด๋ถ์์ ์ ์๋ ํจ์๋ช ์ด๋ค.
# ๋ผ์ฐํ ํจ์
hello_pybo ํจ์๋ / URL๊ณผ ๋งคํ๋๋ ํจ์์ธ๋ฐ, ์ด๋ฌํ URL ๋งคํ์ @app.route('/')๋ผ๋ ์ ๋ํ ์ด์ ์ด ๋ง๋ค์ด ์ค๋ค. ์ด๋ @app.route์ ๊ฐ์ ์ ๋ํ ์ด์ ์ผ๋ก URL์ ๋งคํํ๋ ํจ์๋ฅผ ๋ผ์ฐํ ํจ์๋ผ๊ณ ํ๋ค.
# ORM
ORM(object relational mapping)์ ์ด์ฉํ๋ฉด ํ์ด์ฌ ๋ฌธ๋ฒ๋ง์ผ๋ก๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ค๋ฃฐ ์ ์๋ค.
์ฆ, ORM์ ์ด์ฉํ๋ฉด ๊ฐ๋ฐ์๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์ง์ ์์ฑํ์ง ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
- ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ํ ์ด๋ธ์ ํ์ด์ฌ ํด๋์ค๋ก ๋ง๋ค์ด ๊ด๋ฆฌํ๋ ๊ธฐ์ ๋ก ์ดํดํด๋ ์ข๋ค.
๋น๊ตํ์๋ฉด ์๋์ ๊ฐ์
insert into question (subject, content) values ('์๋ ํ์ธ์', '๊ฐ์ ์ธ์ฌ๋๋ฆฝ๋๋ค ^^'); question1 = Question(subject=’์๋ ํ์ธ์’, content='๊ฐ์ ์ธ์ฌ๋๋ฆฝ๋๋ค ^^') db.session.add(question1)
์ Insert ๋ฌธ์ ๊ธฐ์กด์ sql ์ด๊ณ , ์๋ question1์ด๋ผ๋ ๋ณ์ ์ ์ฟผ๋ฆฌ๋ฌธ์ด ORM์ด๋ค.
# ORM ์ฅ์
1. ORM์ ์ด์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ข ๋ฅ์ ์๊ด ์์ด ์ผ๊ด๋ ์ฝ๋๋ฅผ ์ ์งํ ์ ์์ด์ ํ๋ก๊ทธ๋จ์ ์ ์ง·๋ณด์ํ๊ธฐ๊ฐ ํธ๋ฆฌํ๋ค.
2. ๋ด๋ถ์์ ์์ ํ SQL ์ฟผ๋ฆฌ๋ฅผ ์๋์ผ๋ก ์์ฑํด ์ฃผ๋ฏ๋ก ๊ฐ๋ฐ์๊ฐ ๋ฌ๋ผ๋ ํต์ผ๋ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ ์๋ค.
3. ์ค๋ฅ ๋ฐ์๋ฅ ๋ ์ค์ผ ์ ์๋ค.
4. ํ์ด์ฌ๋ง์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค. ๋ฑ๋ฑ..
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
Flask-Migrate ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ๋ฉด SQLAlchemy๋ ํจ๊ป ์ค์น๋๋ฏ๋ก myproject ๊ฐ์ ํ๊ฒฝ์์ ๋ค์ ๋ช ๋ น์ ์ํํ์ฌ Flask-Migrate ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ์.
# ์ค์ ํ์ผ ์ถ๊ฐ
flask_project ์๋์ config.py ํ์ผ์ ์์ฑํ๊ณ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
import os
BASE_DIR = os.path.dirname(__file__)
SQLALCHEMY_DATABASE_URI = 'sqlite:///{}' .format(os.path.join(BASE_DIR,'pybo.db'))
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_DATABASE_URI ๋ :
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ์ ์ฃผ์
SQLALCHEMY_TRACK_MODIFICATIONS๋ :
SQLAlchemy์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ์ต์ ์ด๋ค. ์ด ์ต์ ์ ํ์ด๋ณด์ ํ์ํ์ง ์์ผ๋ฏ๋ก False๋ก ๋นํ์ฑํ ํ๋ค.
SQLALCHEMY_DATABASE_URI :
์ค์ ์ ์ํด SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ฌ์ฉ๋๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ผ์ ํ๋ก์ ํธ ํ ๋๋ ํฐ๋ฆฌ ๋ฐ๋ก ๋ฐ์ pybo.db ํ์ผ๋ก ์ ์ฅ๋๋ค.
#๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ
๋จผ์ init.py ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํด์ค๋ค.
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
import config
# ์ ์ญ๋ณ์๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ฌ
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.config.from_object(config) #config ํ์ผ์ ์ฝ๊ธฐ ์ํจ์
# ORM
db.init_app(app)
migrate.init_app(app, db)
# ๋ธ๋ฃจํ๋ฆฐํธ
from .views import main_views
app.register_blueprint(main_views.bp)
return app
'''
์ด๋ถ๋ถ์ด ๊ธฐ์กด์ route๋ถ๋ถ์ธ๋ฐ, ๋ธ๋ฃจํ๋ฆฐํธ๋ก view๋ก ๋ฐ๋ก ๋บ์
@app.route('/')
def hello_pybo():
return 'string test'
'''
์ดํ flask db init ๋ช ๋ น์ด๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ด๊ธฐํ ํด์ค๋ค.
๊ทธ๋ผ ์๋์ ๊ฐ์ด migrations ๊ฐ ์๋์ผ๋ก ์๊น
์ค๋ฅธ์ชฝ์ DB๋ช ๋ น์ด 2๊ฐ๋ ๊ผญ ์ธ์ฐ๋ ๊ฒ์ด ์ข๋ค.
# data base query ์์ฑํ๊ธฐ
pybo ์๋ models.py๋ฅผ ์์ฑ ํ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ค. ๊ฐ ์ฝ๋์ ๋ํ ์ค๋ช ์ > https://wikidocs.net/81045 ์ฐธ๊ณ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
from pybo import db
# ์ง๋ฌธ ๋ชจ๋ธ
class Question(db.Model):
id = db.Column(db.Integer, primary_key=True)
subject = db.Column(db.String(200), nullable=False) # nullable์ ๋น ๊ฐ์ ๋ํ ํ์ฉ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ false๋ ๋น ๊ฐ์ด ๋ถํํ๋ค๋ ์๋ฏธ์ด๋ค.
content = db.Column(db.text(), nullable=False)
create_data = db.Column(db.DateTime(), nullable=False)
class Answer(db.Model):
id = db.Column(db.Integer, primary_key=True)
question_id = db.Column(db.Integer, db.ForeignKey('question.id', ondelete='CASCADE'))
question = db.relationship('Question', backref=db.backref('answer_set'))
content = db.Column(db.Text(), nullable=False)
create_date = db.Column(db.DateTime(), nullable=False)
์์ฑ ํ ์ ์ฉํด์ค๋ค.
> flask db migrate
์ ์ฉ ์, ef96 ~~ ๋ผ๊ณ ํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ๊ฒฝ ์์ ์ ์ํ ๋ฆฌ๋น์ ํ์ผ์ด ์์ฑ๋๋ค.
๋ฆฌ๋น์ (revision)์ด๋ ์์ฑ๋ ํ์ผ์์ .py ํ์ฅ์๋ฅผ ์ ์ธํ ef96.._์ ๊ฐ์ ๋ฒ์ ๋ฒํธ๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
๋ฆฌ๋น์ ์ flask db migrate ๋ช ๋ น์ ์ํํ ๋ ๋ฌด์์๋ก ๋ง๋ค์ด์ง๋ค.
์ด์ด์ flask db upgrade ๋ช ๋ น์ผ๋ก ๋ง๋ค์ด์ง ๋ฆฌ๋น์ ํ์ผ์ ์คํํ์. (๋ฆฌ๋น์ ํ์ผ ๋ด์๋ ํ ์ด๋ธ ์์ฑ์ ์ํ ์ฟผ๋ฆฌ๋ฌธ๋ค์ด ์ ์ฅ๋์ด ์๋ค.) -> pybo.db๊ฐ ์์ฑ๋จ => pybo.db๊ฐ ๋ฐ๋ก SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ ํ์ผ์ด๋ค.
'Languages > Python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋น์ ์ด ์ข์ํ ๋งํ ์ฝํ ์ธ
-
[flask] Do it ์ ํ ํฌ ํ๋ผ์คํฌ _ 1. ํ๊ฒฝ ๊ตฌ์ฑ ๋ฐ ์๋ฒ ์คํ 2022.04.13
-
[์ํธํ๋กํ ์ฝ] Diffie-Hellman ํค ์๊ณ ๋ฆฌ์ฆ ์ฝ๋ ๊ตฌํ 2021.05.20
-
[์ํธ ํ๋กํ ์ฝ] ์ ์์๋ช ๊ตฌํํ๊ธฐ 2021.05.14
-
[์ํธ ํ๋กํ ์ฝ] ๋์งํธ ์๋ช | ์ ์์๋ช ์ ์ํ ์๋ณตํธํ | ๊ณต๊ฐํค ์ฌ์ฉ์ ์ํ ์๋ณตํธํ 2021.05.06
์์คํ ๊ณต๊ฐ ๊ฐ์ฌํฉ๋๋ค