[requirements.txt]
Flask==2.0.2
mysql-connector-python==8.0.27
Flask-SQLAlchemy==2.5.1
Flask-Migrate==3.1.0
alembic==1.7.5
Jinja2==3.0.3
psycopg2-binary==2.9.3
python-dotenv==0.19.2
여기서 유의할 건 psycopg2인데, 나 같은 경우 맥 유저라서 그런 지 자꾸 psycopg2를 pip3으로 설치하려고 하니까 에러 메시지가 잔뜩 떴다.
그래서 스택오버플로우를 참고해 그냥 그 대안인 psycopg2-binary 를 설치해 주었다.
참고로 psycopg2-binary로 설치해도 python 코드로 import할 때는 psycopg2로 해주어도 된다.
일단 클리한 코드는 나중에 차차 리팩토링해주는 걸로 하고, 당장 flask-sqlalchemy-postgres 연결이 시급했기 때문에 구글링해서 찾은 블로그를 참고해 코드를 작성해 보았다. 대신, 나는 .env를 써줬다.
pgadmin을 사실 mac local에 설치해서 쓸 수도 있었지만, 일단 한번 생소한 도커를 더 써주고 싶어서 이렇게 구성해 봤다.
import os
user = os.getenv('PG_USER')
password = os.getenv('PG_PASSWORD')
host = os.getenv('PG_HOST')
database = os.getenv('PG_DB')
port = os.getenv('PG_PORT')
DATABASE_CONNECTION_URI = f'postgresql+psycopg2://{user}:{password}@{host}:{port}/{database}'
import flask_sqlalchemy
db = flask_sqlalchemy.SQLAlchemy()
class Cats(db.Model):
__tablename__ = 'cats'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
price = db.Column(db.Integer)
breed = db.Column(db.String(100))
from flask import Flask
from .models import db
from . import config
import os
def create_app():
flask_app = Flask(__name__)
flask_app.config['SQLALCHEMY_DATABASE_URI'] = config.DATABASE_CONNECTION_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
flask_app.app_context().push()
db.init_app(flask_app)
db.create_all()
return flask_app
from .models import db
def get_all(model):
data = model.query.all()
return data
def add_instance(model, **kwargs):
instance = model(**kwargs)
db.session.add(instance)
commit_changes()
def delete_instance(model, id):
model.query.filter_by(id=id).delete()
commit_changes()
def edit_instance(model, id, **kwargs):
instance = model.query.filter_by(id=id).all()[0]
for attr, new_value in kwargs.items():
setattr(instance, attr, new_value)
commit_changes()
def commit_changes():
db.session.commit()
import json
from flask import request
from . import create_app, database
from .models import Cats
app = create_app()
@app.route('/', methods=['GET'])
def fetch():
cats = database.get_all(Cats)
all_cats = []
for cat in cats:
new_cat = {
"id": cat.id,
"name": cat.name,
"price": cat.price,
"breed": cat.breed
}
all_cats.append(new_cat)
return json.dumps(all_cats), 200
@app.route('/add', methods=['POST'])
def add():
data = request.get_json()
name = data['name']
price = data['price']
breed = data['breed']
database.add_instance(Cats, name=name, price=price, breed=breed)
return json.dumps("Added"), 200
@app.route('/remove/<cat_id>', methods=['DELETE'])
def remove(cat_id):
database.delete_instance(Cats, id=cat_id)
return json.dumps("Deleted"), 200
@app.route('/edit/<cat_id>', methods=['PATCH'])
def edit(cat_id):
data = request.get_json()
new_price = data['price']
database.edit_instance(Cats, id=cat_id, price=new_price)
return json.dumps("Edited"), 200
PG_DB=pgdb
PG_USER=postgres
PG_PASSWORD=1111
PG_HOST=postgres
PG_PORT=5432
PG_ADMIN_EMAIL=leejin21c@gmail.com
PGADMIN_DEFAULT_PASSWORD=PassW@rd!!
FLASK_ENV=development
FLASK_DEBUG=True
version: "3.8"
services:
web:
build:
context: .
env_file:
- .env
ports:
- 5000:5000
environment:
- FLASK_APP=./src/app.py
volumes:
- ./:/app
postgres:
container_name: postgres
image: postgres:latest
ports:
- 5432:5432
environment:
- POSTGRES_DB=${PG_DB}
- POSTGRES_USER=${PG_USER}
- POSTGRES_PASSWORD=${PG_PASSWORD}
volumes:
- postgres:/var/lib/postgres
pgadmin:
container_name: pgadmin
image: dpage/pgadmin4
ports:
- 8088:80
environment:
- PGADMIN_DEFAULT_EMAIL=${PG_ADMIN_EMAIL}
- PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
volumes:
postgres:
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0"]
Flask==2.0.2
mysql-connector-python==8.0.27
Flask-SQLAlchemy==2.5.1
Flask-Migrate==3.1.0
alembic==1.7.5
Jinja2==3.0.3
psycopg2-binary==2.9.3
python-dotenv==0.19.2
위와 같이 post 요청을 하면, 아래와 같이 get 요청을 했을 때 동일한 데이터가 뜬다.
pgadmin에서도 다음과 같이 잘 뜬다.
계속 컨테이너를 올리는데 웹 컨테이너가 안 올라가서 한참을 구글링하다가 스택오버플로우 보니까
(에러 내용: db.create_all()이 문제야~! localhost에 없더라~)
DB_HOST에 localhost로 하면 안되고, docker-compose.yml에서 postgres에 할당한 컨테이너의 이름으로 해줘야 하더라.
그래서 .env 파일을 다음과 같이 구성함.
아 그리고 PG_PASSWORD에 골뱅이(@) 들어가는 걸로 안 설정하는 게 좋은 듯.
→ 에러 생기고 주소가 이상하다고 뜨기 때문.
PG_DB=pgdb
PG_USER=postgres
PG_PASSWORD=1111
PG_HOST=postgres
PG_PORT=5432
PG_ADMIN_EMAIL=leejin21c@gmail.com
PGADMIN_DEFAULT_PASSWORD=PassW@rd!!
FLASK_ENV=development
FLASK_DEBUG=True