파이썬 코드에서 DB와 연결하기 위해 사용할 수 있는 다양한 라이브러리가 있는데,
SQLAlchemy라는 라이브러리는 가장 널리 쓰이는 라이브러리 중 하나이다.
📌️ SQLAlchemy는 ORM(Object Relational Mapper)이다.
ORM이란, 관계형 데이터베이스의 테이블들을 프로그래밍 언어의 클래스로 표현할 수 있게 해주는 것을 말한다.
즉, 클래스(class)를 사용해서 테이블들을 표현하고 데이터를 저장, 읽기, 업데이트 등을 할 수 있게 해준다.
하지만 여기서는 ORM 부분은 사용하지 않고 CORM 부분(데이터베이스와의 연결)만을 사용할 것이다.
처음부터 ORM을 사용하면 SQL을 배울 수가 없기 때문이다.
다음 명령어를 실행한다.
pip install sqlalchemy
SQLAlchemy에서 MySQL을 사용하기 위해서는 MySQL용 DBAPI 또한 설치해야 한다.
DBAPI는 이름 그대로 DB를 사용하기 위한 API이다.
그 중 MySQL의 공식 파이썬 DBAPI인 MySQL-Connector를 사용하도록 한다.
pip install mysql-connector-python
앞서 말했듯이 SQLAlchemy를 사용하여 데이터베이스에 연결하여 SQL을 실행시켜 데이터베이스로부터
데이터를 읽어 들이거나 생성하거나 할 수 있다.
예를 들어, users 테이블에서 사용자의 이름과 이메일을 다음과 같이 읽어 들일 수 있다.
from sqlalchemy import create_engine, text
db = {
'user' : 'root',
'password' : 'test1234',
'host' : 'localhost',
'port' : 3306,
'database' : 'miniter'
}
db_url = f"mysql+mysqlconnector://{username}:{password}@{host}:
{port}/{database}?charset=utf8"
db = create_engine(db_url, encoding = 'utf-8', max_overflow = 0)
params = {'name' : 'Moses'}
rows = db.execute(text("SELECT * FROM users WHERE name = :name"),
params).fetchall()
for row in rows:
print(f"name : {row['name']}")
print(f"email: {row['email']}")
from sqlalchemy import create_engine, text
db = {}
db_url = f"mysql+mysqlconnector://{username}:{password}@{host}:{port}/{database}? charset=utf8"
db = create_engine(db_url, encoding = 'utf-8', max_overflow = 0)
rows = db.execute(text("SELECT * FROM users WHERE name = :name"), params).fetchall()
for row in rows: print(f"name : {row['name']}") print(f"email: {row['email']}")
이제 실제로 미니터 API를 MySQL 데이터베이스에 연결하도록 한다.
먼저, 데이터베이스의 연결 정보를 저장할 파일인 config.py을 만들어 두자.
그리고 아래와 같이 데이터베이스 연결 정보를 저장시켜 놓는다.
'user' : 'root',
'password' : 'test1234',
'host' : 'localhost',
'port' : 3306,
'database' : 'miniter'
📌️ 이렇게 설정 파일을 따로 만드는 이유는 2가지이다.
첫 번째는, 설정 정보를 따로 관리함으로써 민감한 개인 접속 정보를 노출하지 않아도 된다.
두 번째는, 각 환경과 설정에 맞는 설정 파일을 적용할 수 있게 된다.
.gitignore 파일에 config.py파일을 지정해 놓음으로써 config.py 파일이 git 레포지토리에 포함되지 않게 하므로 개인정보 노출을 막고, 각 개발 호스트 혹은 서버에 맞는 config.py을 생성하도록 함으로써 각 환경에 적합한 설정을 적용하도록 하는 것이다.
이제 app.py 파일을 수정하여 config.py파일에서 데이터베이스 설정 정보를 읽어들여 데이터베이스와 연결하도록 할 것이다.
이미 본 대로 sqlalchemy의 create_engine을 사용하여 데이터베이스를 연결한다.
from flask import Flask, jsonify
from sqlalchemy import create_engine, text
def create_app(test_config = None):
app = Flask(__name__)
if test_config is None:
app.config.from_pyfile("config.py")
else:
app.config.update(test_config)
database = create_engine(app.config['DB_URL'], encoding = 'utf-8',
max_overflow = 0)
app.database = database
return app
def create_app(test_config = None):
def create_app(test_config = None):
database = create_engine(app.config['DB_URL'], encoding = 'utf-8', max_overflow = 0)
app.database = database
return app
이제 create_app 함수 안에 엔드포인트들을 구현할 것이다.
그리고 엔드포인트들을 구현할 때 앞서 본 대로 sqlalchemy를 사용하여 MySQL 데이터베이스에 연결하여 데이터를 데이터베이스에 저장 및 읽어 들이도록 할 것이다.
먼저 회원가입 엔드포인트를 데이터베이스를 사용해서 구현하도록 한다.
기본적인 구조는 이전에 구현했던 것과 동일하다.
다만 데이터를 하드코드하거나 메모리상에 저장하지 않고 데이터베이스에 저장한다.
@app.route("/sign-up", methods=['POST'])
def sign_up():
new_user = request.json
new_user_id = app.database.execute(text("""
INSERT INTO users (
name,
email,
profile,
hashed_password
) VALUES (
:name,
:email,
:profile,
:password
)
"""), user).lastrowid
row = current_app.database.execute(text("""
SELECT
id,
name,
email,
profile
FROM users
WHERE id = :user_id
"""), {
'user_id' : user_id
}).fetchone()
create_user = {
'id' : user['id'],
'name' : user['name'],
'email' : user['email'],
'profile' : user['profile']
} if user else None
return jsonify(created_user)
Explanation
new_user_id = app.database.execute(text("""
...
"""), user).lastrowid
row = current_app.database.execute(text("""
...
create_user = {
...
sign-up 엔드포인트는 다음의 명령어를 실행함으로써 테스트 할 수 있다.
http -v POST "http://localhost:5000/sign-up" \ name=Moses \ email=ssm2319@gmail.com \ password=test1234 \ profile="Christian. Student"
그런데 필자는 이 부분부터 진행이 안된다..
2달 전쯤에 책을 처음 읽었을 때에도 여기서 막혔는데.. 지금도 똑같다..
터미널 1
터미널 2
...
...
...
sqlalchemy.exc.ProgrammingError: (mysql.connector.errors.ProgrammingError) 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
이 에러를 해결하지 못하겠다.
이전 게시글에서 똑같은 종류의 에러를 봤을 때는 비밀번호를 설정함으로써 해결하였는데
이 경우는 mysql의 비밀번호 유무와 상관없이 똑같은 메시지가 출력된다..
stackoverflow를 아무리 뒤져봐도 방법을 모르겠다..
mySQL의 DBAPI인 MySQL-Connector에 문제가 있는 것 같은데..
저자의 깃허브에서 모든 코드를 복사해와도 모든 http명령어가 에러가 뜬다.