데이터베이스를 사용해서 처리
ORM(object relational mapping)을 사용해서 파이썬 문법으로 데이터베이스 처리
○데이터베이스 종류에 관계 없이 일관된 코드를 유지할 수 있어서 프로그램 유지, 보수가 편리
○내부에서 안전한 SQL쿼리를 자동으로 생성해 개발자가 달라도 동일한 쿼리 작성 가능, 오류 발생률을 줄임
ORM을 적용하기 위해 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
pybo폴더에 __init__.py라는 파일을 수정해 SQLAlchemy 적용
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)
#ORM
db.init_app(app)
migrate.init_app(app, db)
from . import models
#blueprint
from .views import main_views
app.register_blueprint(main_views.bp)
return app
데이터베이스 초기화
(mypro) C:\projects\mypro>flask db init
Creating directory C:\projects\mypro\migrations ... done
Creating directory C:\projects\mypro\migrations\versions ... done
Generating C:\projects\mypro\migrations\alembic.ini ... done
Generating C:\projects\mypro\migrations\env.py ... done
Generating C:\projects\mypro\migrations\README ... done
Generating C:\projects\mypro\migrations\script.py.mako ... done
Please edit configuration/connection/logging settings in 'C:\\projects\\mypro\\migrations\\alembic.ini' before proceeding.
flask db migrate | 모델을 새로 생성하거나 변경할 때 사용(실행하면 작업파일이 생성됨) |
flask db upgrade | 모델의 변경 내용을 실제 데이터베이스에 적용할 때 사용(위에서 생성된 작업파일을 실행하여 데이터베이스를 변경) |
질문과 답변 모델 생성
C:/projects/mypro/pybo/models.py
from pybo import db
#질문
class Question(db.Model) :
id = db.Column(db.Integer, primary_key=True) #고유번호
subject = db.Column(db.String(200), nullable=False) #제목
content = db.Column(db.Text(), nullable=False) #내용
create_date = 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)
primary_key : 기본키
nullable : 빈값을 허용할 것인지 결정, 지정하지 않으면 기본으로 빈값 허용
ForeignKey : 외부키, 어떤 속성을 기존 모델과 연결할 때 사용
CASCADE: 무결성참조, 답변 모델의 question_id 속성이 질문 모델의 id속성과 연결되며 데이터베이스에서 쿼리를 이용하여 질문을 삭제하면 해당 질문에 달린 답변도 함께 삭제된다.
명령프롬포트(cmd)에서 실행
(mypro) C:\projects\mypro>flask db migrate
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'question'
INFO [alembic.autogenerate.compare] Detected added table 'answer'
Generating C:\projects\mypro\migrations\versions\8ca5ef5222e4_.py ... done
데이터베이스 갱신
(mypro) C:\projects\mypro>flask db upgrade
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 8ca5ef5222e4, empty message
모델 사용하기
(mypro) C:\projects\mypro>flask shell
Python 3.10.2 (tags/v3.10.2:a58ebcc, Jan 17 2022, 14:12:15) [MSC v.1929 64 bit (AMD64)] on win32
App: pybo [development]
Instance: C:\projects\mypro\instance
>>>
Question 모델 객체 생성
>>> from pybo.models import Question, Answer
>>> from datetime import datetime
>>> q = Question(subject='pybo가 무엇인가요?', content='pybo에 대해서 알고 싶습니다.',create_date=datetime.now())
datetime.now() 함수로 현재 일시 대입
>>> from pybo import db
>>> db.session.add(q)
>>> db.session.commit()
커밋까지 완료해야 데이터베이스에 저장이 완료된다.
커밋은 취소할 수 없으니 취소하고 싶으면 db.session.rollback()으로 되돌리기를 실행하자
>>> q.id
1
데이터가 잘 생성되었는지 확인!
>>> q = Question(subject='플라스크 모델 질문입니다.',content='id는 자동으로 생성되나요?',create_date=datetime.now())
>>> db.session.add(q)
>>> db.session.commit()
>>> q.id
2
primary_key로 id가 자동으로 1씩 증가하기 때문에 다음 질문의 id는 2가 되었다
>>> Question.query.all()
[<Question 1>, <Question 2>]
데이터베이스에 저장된 질문 데이터를 모두 조회한다. Question 객체 리스트를 반환한다
>>> Question.query.filter(Question.id==1).all()
[<Question 1>]
첫번째 질문데이터만 조회
filter 함수는 인자로 전달한 조건에 맞는 데이터를 모두 반환해준다. 기본 키인 id를 이용했으므로 값을 1개만 반환한다.
id는 유일한 값이므로 filter 함수 대신 get 함수를 이용해 조회할 수도 있다.
>>> Question.query.get(1)
<Question 1>
>>> Question.query.filter(Question.subject.like('%플라스크%')).all()
[<Question 2>]
>>> Question.query.filter(Question.subject.ilike('%pybo%')).all()
[<Question 1>]
like로 subject 속성에 '플라스크'라는 문자열이 포함된 데이터를 조회할 수 있다.
- 플라스크%: "플라스크"로 시작하는 문자열
- %플라스크: "플라스크"로 끝나는 문자열
- %플라스크%: "플라스크"를 포함하는 문자열
ilike 함수 : 대소문자 구분하지 않고 문자열을 찾으려면 사용
질문 데이터 수정하기
>>> q = Question.query.get(2)
>>> q
<Question 2>
>>> q.subject = 'Flask Model Question'
>>> db.session.commit()
두번째 질문 데이터를 조회한 다음 subject 속성을 수정했다.
데이터 삭제하기
>>> q = Question.query.get(1)
>>> db.session.delete(q)
>>> db.session.commit()
답변 데이터 생성 후 저장하기
>>> from datetime import datetime
>>> from pybo.models import Question, Answer
>>> from pybo import db
>>> q = Question.query.get(2)
>>> a = Answer(question=q, content='네 자동으로 생성됩니다.', create_date=datetime.now())
>>> db.session.add(a)
>>> db.session.commit()
답변 데이터를 생성하기 위해서는 질문 데이터가 필요하므로 우선 질문 데이터를 구해야한다.
id가 2인 질문데이터를 가져온 다음 q에 저장했다. 그 다음 Answer모델의 question 속성에 방금 가져온 q를 대입해 답변 데이터를 생성했다.
답변에 연결된 질문 찾기
>>> a.question
<Question 2>
질문에 연결된 답변 찾기
>>> q.answer_set
[<Answer 1>]
역참조 설정인 backref=db.backref('answer_set')로 할 수 있다
플라스크 쉘에서 빠져나오려면 ctrl+z를 누르고 <Enter>를 입력한다.
파이썬 가상환경에 진입하려면
cmd창에 mypro라고 배치 파일명을 실행한다