시작에 앞서
해당 내용은 <가장 빠른 풀스택을 위한 Flask & FastAPI>, Dave Lee 지음. BJ Public 출판.
내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.
이전 내용
플라스크와 MySQL 연동 - User 모델 생성
기본적인 플라스크 애플리케이션을 설정하고 SQLAlchemy를 설정한 뒤, User 모델을 생성한다.
User 모델 생성은 데이터베이스에 정의한 테이블을 생성하는 것인데, User 클래스는 user라는 이름의 테이블을 만드는 것을 말한다.
class User(db.Model):
# 테이블 이름 직접 지정(생략 시 클래스이름은 'user')
__tablename__ = 'users'
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 __repr__(self):
return '<User %r>' % self.username
▶각 코드별 설명
class User(db.Model):
__tablename__ = 'users'
User 클래스는 SQLAlchmey의 Model 클래스를 상속받으며, __tablename__ 속성을 통해 데이터베이스에서 사용할 테이블의 이름을 users로 명시적으로 지정한다.
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)
컬럼을 정의한다.
- db.Column(): 테이블의 컬럼 정의
- db.Integer, db.String(x): 데이터 타입 지정. id는 정수형, username과 email은 문자형
- primary_key=True: id 컬럼을 테이블의 기본 키로 지정
- unique=True: username과 email 컬럼에는 고유한 값만 저장되어야 함을 나타냄
- nullable=False: 컬럼에 Null 값이 들어갈 수 없음
def __repr__(self):
return '<User %r>' % self.username
repr() 메서드 사용
- __repr__: 객체의 문자열 표현 정의. 콘솔에 객체를 출력할 때 이 메서드가 반환하는 형식대로 출력
★ SQLAlchemy는 내부적으로 생성자를 제공하기 때문에, 모델 클래스에 명시적으로 생성자(__init__)를 정의하지 않아도 된다. 이 내부 생성자는 모델에 선언한 컬럼과 일치하는 키워드 인자를 받아 인스턴스를 초기화한다.
플라스크 애플리케이션은 실행될 때 '컨텍스트(특정한 실행 환경)'를 가진다.
이 컨텍스트는 현재 애플리케이션이나 요청에 대한 정보를 담고 있으며, 애플리케이션 레벨의 텍스트를 '애플리케이션 컨텍스트' 라고 하며, SQLAlchemy를 사용하여 DB와 상호 작용할 때 이 애플리케이션 컨텍스트 안에서 실행해야 할 작업들이 있다.
# 애플리케이션 컨텍스트 안에서 DB 테이블 생성
with app.app_context():
# db.create_all() 메서드는 모델에 정의된 모든 테이블을 데이터베이스에 생성
db.create_all()
▶ app.app_context()를 사용하여 명시적으로 애플리케이션 컨텍스트를 생성하고, with문에서 db.create_all() 호출.
이는 플라스크 애플리케이션의 컨텍스트 내에서 실행되어야 하는 작업들을 위해 필요하다.
db.create_all() 메서드는 모델 클래스를 통해 정의된 모든 테이블을 데이터베이스에 생성하는 SQLAlchemy의 내장 메서드이다.
(애플리케이션을 처음 실행할 때 데이터베이스를 초기화하는 데 주로 사용)
create_all() 메서드는 현재 애플리케이션의 데이터베이스 설정에 따라 적절한 데이터베이스에 테이블들을 생성한다.
CRUD 구현
CRUD: Create, Read, Update, Delete의 약자로, 데이터베이스에서 가장 기본적인 작업
◆ Create: 데이터 추가하기
데이터를 새로 생성하려면 모델 클래스의 인스턴스를 만들고, 이를 db.session.add()와 db.session.commit()으로 데이터베이스에 추가한다.
new_user = User(username='john', email='john@example.com') # 새 인스턴스 생성
db.session.add(new_user) # 새로운 사용자를 데이터베이스 세션에 추가
db.session.commit() # 변경 사항을 데이터베이스에 실제로 반영
◆ Read: 데이터 읽기
가장 기본적인 데이터를 읽는 방법은 query 객체를 사용하는 것이다.
user = User.query.filter_by(username='john').first()
- User.query: User 모델에 대한 query 객체 생성
- filter_by(username='john'): username이 'john'인 레코드 필터링
- first(): 필터링된 레코드 중 첫 번째 레코드를 가져옴
그 밖의 메서드
users = User.query.all() # 모든 레코드 가져오기
user = User.query.get(1) # id가 1인 User 레코드 가져옴
# filter() 메서드 사용하기
users = user.query.filter(User.email.endswith('@gmail.com')).all()
# filter_by는 간단한 조건
user = User.query.filter_by(username='john').first()
# limit() 메서드로 가져올 레코드의 개수 제한
users = User.query.limit(5).all() #처음 5개의 레코드
# offset() 메서드로 몇 개의 레코드를 건너뛸지 설정
users = User.query.offset(2).all() # 처음 두 개 건너뛰고 나머지 User 레코드 가져옴
# order_by() 메서드로 결과 정렬
users = User.query.order_by(User.username).all() #오름차순 정렬
# count() 메서드로 조건에 맞는 레코드의 개수 세기
count = User.query.filter_by(username='john').count()
# startswith 메서드는 특정 문자열로 시작하는 레코드 찾음
users = User.query.filter(User.email.startswith('john').all()
# %와 _와일드카드 문자를 사용하여 더 복잡한 문자열 매칭 가능
# %는 0개의 문자, _는 하나의 문자 의미
users = User.query.filter(User.email.like('%mail%')).all()
# ilike() 메서드는 대소문자를 구분하지 않음
users = User.query.filter(User.email.ilike('%GMAIL%')).all()
# contains()는 특정 문자열을 포함하는 레코드 찾음
users = User.query.filter(User.email.contains('gmail')).all()
# in_() 메서드는 주어진 리스트에 있는 값 중 하나와 일치하는 레코드 찾음
users = User.query.filter(User.username.in_(['john', 'susan'])).all()
# func 모듈을 사용하여 소문자나 대문자로 변환 가능
# filter()와 함께 사용하면 대소문자를 구분하지 않는 검색 가능
from sqlalchemy import func
users = User.query.filter(func.lower(User.email) == 'john@gmail.com').all()
또한 여러 메서드를 체인으로 연결하여 사용할 수 있다.
user = User.query.filter_by(username='john').first()
user = User.query.filter(User.email.endswith('@gmail.com')).limit(5).all()
◆ Update: 데이터 수정하기
데이터를 수정하려면 먼저 해당 데이터를 읽어와야 한다.
그리고나서 변경 사항을 적용하고 db.session.commit()을 호출한다.
[SQLAlchemy에서 여러 레코드를 한 번에 수정하는 방법]
1. 먼저 조건에 맞는 여러 레코드를 읽어온 뒤, 각 레코드를 수정하고 마지막에 한 번에 커밋하는 방식
users = User.query.filter_by(username='john').all() # username이 john인 모든 레코드 가져옴
for user in users:
user.email = 'john@newexample.com' # 각 사용자의 email 필드 수정
db.session.commit() # 변경 사항을 데이터베이스에 반영
2. update() 메서드 사용 (여러 레코드를 한 번의 쿼리로 수정)
이 방법은 데이터베이스 서버에 바로 적용되므로 db.session.commit() 을 호출할 필요가 없다.
User.query.filter_by(username='john').update({ 'email': 'john@newexample.com' })
db.session.commit()
※ Update() 메서드는 FLUSH 작업을 수행하지 않기 때문에, 이전에 로드된 객체가 있다면 이 객체들의 상태는 자동으로 업데이트 되지 않는다. 따라서 현재 세션 내에 이미 로드된 객체가 있고 그 상태를 유지하고 싶다면, db.session.refresh(obj)를 사용하여 수동으로 갱신해야 한다.
◆ Delete: 데이터 삭제하기
데이터를 삭제하려면 먼저 해당 데이터를 읽어온 후, db.session.delete()와 db.session.commit()을 호출해야 한다.
user = User.query.filter_by(username='john').first()
db.session.delete(user) # 데이터베이스 세션에서 해당 사용자 삭제
db.session.commit()
애플리케이션 실행
[전체 코드]
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 데이터베이스 연결 URI 설정
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:password@localhost:3306/db_name'
# SQLAlchemy 인스턴스 초기화
db = SQLAlchemy(app)
# 데이터베이스 모델 정의
class User(db.Model):
# 테이블 이름 직접 지정(생략 시 클래스이름은 'user')
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True) # 사용자 id 기본키로 설정
username = db.Column(db.String(80), unique=True, nullable=False) # 사용자 이름, 중복 불가 및 필수 입력
email = db.Column(db.String(120), unique=True, nullable=False) # 이메일 주소, 중복 불가 및 필수 입력
def __repr__(self):
return '<User %r>' % self.username # 갹체를 문자열로 표현할 때 사용할 형식
# 애플리케이션 컨텍스트 안에서 DB 테이블 생성
with app.app_context():
# db.create_all() 메서드는 모델에 정의된 모든 테이블을 데이터베이스에 생성
db.create_all()
# 라우트 정의
@app.route('/')
def index():
# 데이터 생성
new_user = User(username='john', email='john@example.com')
db.session.add(new_user)
db.session.commit()
# 데이터 조회
user = User.query.filter_by(username='john').first()
# 데이터 업데이트
user.email = 'john@newexample.com'
db.session.commit()
# 데이터 삭제
db.session.delete(user)
db.session.commit()
return 'CRUD operations completed'
★ 파이썬 내에서도 MySQL 데이터베이스를 생성할 수 있다.
import pymysql
conn = pymysql.connect(host='localhost',
user='testuser',
password='password!@',
charset='utf8')
with conn:
with conn.cursor() as cur:
cur.execute('CREATE DATABASE testdb')
conn.commit()
그리고나서 MySQL을 켜고 아래의 명령어를 입력하면,
SHOW DATABASES;
'testdb' 데이터베이스가 잘 생성성된 것을 확인할 수 있다.
vscdoe 터미널에서 flask run을 실행한 후,
http://127.0.0.1:5000/ 에 접속하면
[코드 내용 설명]
- 데이터 생성(Create): 'john' 이라는 username과 'john@example.com' 이라는 email을 가진 새로운 User 객체가 생성되고, 데이터베이스에 커밋된다.
- 데이터 조회(Read): username이 'john'인 User 객체를 조회한다
- 데이터 업데이트(Update): 조회된 User 객체의 email을 'john@newexample.com' 으로 변경하고 데이터베이스에 커밋한다
- 데이터 삭제(Delete): 조회된 User 객체를 데이터베이스에서 삭제하고 커밋한다
- 결과: 이 모든 CRUD 작업이 성공적으로 완료되면, 서버는 'CRUD operations completed' 라는 메시지를 반환한다
앞의 코드는 한 번의 HTTP 요청으로 모든 CRUD 작업을 수행한다. 실제 애플리케이션에서는 이러한 작업들을 개별적인 API 엔드포인트로 분리하여 처리하는 것이 일반적이다.
또한, 데이터 삭제가 포함되어 있기 때문에 이 URL을 한 번 요청할 때마다 'john' 사용자는 생성되고 삭제되기 때문에 페이지를 새로고침할 때마다 'john' 사용자는 다시 생성되고 삭제된다.
다음 내용
'[파이썬 Projects] > <파이썬 웹개발>' 카테고리의 다른 글
[파이썬] 플라스크(Flask) - 인증과 세션(1) (3) | 2024.07.20 |
---|---|
[파이썬] 플라스크(Flask) - 데이터베이스 (3) (2) | 2024.07.20 |
[파이썬] 플라스크(Flask) - 데이터베이스 (1) (0) | 2024.07.16 |
[파이썬] 플라스크(Flask) - 로깅 (0) | 2024.07.16 |
[파이썬] 플라스크(Flask) - 세션과 쿠키 (0) | 2024.07.15 |