[FastAPI] FastAPI + Streamlit + PostgresSQL (1)
이전 내용
[SQL] PostgreSQL: pg Admin 사용하기
이전 내용 [SQL] PostgresSQL 다운로드 하기PostgresSQL 란? PostgreSQL은 오픈 소스 객체-관계형 데이터베이스 관리 시스템(ORDBMS)으로, 많은 기능과 뛰어난 성능, 유연성을 제공하는 데이터베이스이다. [주
puppy-foot-it.tistory.com
FastAPI + Streamlit + PostgreSQL
조합으로 대시보드 페이지 만들기
FastAPI + Streamlit + PostgreSQL의 조합으로 대시보드 페이지를 만들어본다.
이 프로젝트는 MVC 패턴을 따르며, 각 개발도구는 다음의 역할을 한다.
- 모델 (Model): PostgreSQL
- 데이터베이스는 애플리케이션의 데이터 모델을 정의하고, 데이터를 저장하며, 데이터를 처리하는 역할.
- 뷰 (View): Streamlit
- 사용자 인터페이스를 제공하는 컴포넌트들로 구성되어 있으며, 사용자가 데이터를 입력하고 결과를 시각화하는 부분 담당.
- 컨트롤러 (Controller): FastAPI
- 클라이언트의 요청을 처리하고, 비즈니스 로직을 실행하며, 모델에서 데이터를 가져오고, 뷰에 데이터를 전달하는 역할.
대략적인 진행 순서
- PostgreSQL (pg Admin)을 통해 데이터베이스, 테이블 생성
- FastAPI (VS Code)를 통해
- 가상 환경 만들기 (가상 환경명: my_shop)
- 가상 환경에 필요한 라이브러리 설치하기
- PostgreSQL 연결하기
- 가상 데이터(Faker 라이브러리) 생성
- 생성된 데이터 데이터베이스에 삽입하기 ▶ 1편
- 고객 더미 데이터, 마케팅 더미 데이터 수정 및 추가
- 데이터 분석 함수 만들기
- FastAPI로 API 기능 구현하기
- 포스트맨으로 테스트 하기
- Streamlit (VS Code) 을 통해
- Streamlit과 FastAPI 연동하기
- Streamlit 데이터분석 시각화 함수 구현하기
- Streamlit 실행하여 확인하기
PostgreSQL 로 데이터베이스, 테이블 생성하기
- 데이터베이스 이름: shop
- 테이블: 총 6개 (customers, sales, reviews, payments, products, marketing)
테이블을 생성하고 나면 하단의 ERD 처럼 보여야 한다.
※ ERD: Entity Relationship Diagram의 약자로, 데이터베이스 구조를 시각적으로 표현하는 모델링 기법.
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
phone VARCHAR(20),
gender VARCHAR(10),
birth_date DATE,
registration_date DATE DEFAULT CURRENT_TIMESTAMP,
userid VARCHAR(20) UNIQUE,
passwd VARCHAR(310)
)
CREATE TABLE products
(
product_id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
category VARCHAR(100),
price DECIMAL(10, 2) NOT NULL,
stock_quantity INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
CREATE TABLE marketing
(
marketing_id SERIAL PRIMARY KEY,
campaign_name VARCHAR(255) NOT NULL,
target_audience VARCHAR(255),
budget DECIMAL(10,2),
start_date DATE,
end_date DATE
)
CREATE TABLE sales
(
sale_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id),
product_id INT REFERENCES products(product_id),
quantity INT NOT NULL,
total_price DECIMAL(10,2) NOT NULL,
sale_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
marketing_id INT REFERENCES marketing(marketing_id)
)
CREATE TABLE payments
(
payment_id SERIAL PRIMARY KEY,
sale_id INT REFERENCES sales(sale_id),
payment_method VARCHAR(50) NOT NULL,
payment_status VARCHAR(50) NOT NULL,
payment_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
CREATE TABLE reviews
(
review_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id),
product_id INT REFERENCES products(product_id),
rating INT CHECK(rating BETWEEN 1 AND 5),
review_text TEXT,
review_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
anaconda prompt 가상환경 만들기
새로운 프로젝트 폴더를 생성한 후, anaconda prompt를 켜고 가상환경을 생성한다.
# 설치할 경로로 이동 후
conda create -n my_shop
그리고 VS Code를 켜고 인터프리터에서 좀 전에 만든 가상환경을 선택해 주면 된다.
만약, VSCode 터미널에서 'conda'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다.
라는 에러가 발생하면 ctrl+shift+p 누르고
Terminal: Select Default Profile를 선택한 뒤,
Command Prompt를 선택한 후 재시작을 하면 해결이 된다.
가상환경을 실행한 후,
conda activate my_shop
필요한 라이브러리 (FastAPI, Streamlit 등)를 다운 받는다.
근데, 코드를 여러 번 치는 것은 너무 불편하므로, 파일을 하나 만들어서 해당 파일에 필요한 라이브러리와 모듈을 적어놓고 올리는 방법도 있다.
pip freeze > requirements.txt
pip install -r requirements.txt
[설치한 주요 라이브러리]
- FastAPI: 고성능의 웹 프레임워크로, 빠른 API 구축을 지원하며 비동기 프로그래밍 지원.
- Streamlit: 데이터 애플리케이션을 쉽게 만들 수 있는 프레임워크로, Python 코드로 대화형 웹 앱 생성.
- psycopg2: PostgreSQL 데이터베이스와 Python 애플리케이션 간의 상호 작용을 위한 PostgreSQL 드라이버.
- SQLAlchemy: SQL 데이터베이스와의 상호작용을 위한 객체 관계 매핑(ORM) 라이브러리로, 데이터베이스 쿼리를 보다 직관적으로 작성할 수 있게 해준다.
- scikit-learn: 머신러닝을 위한 라이브러리로, 다양한 알고리즘, 데이터 전처리 및 모델 평가 도구 제공.
- matplotlib: 데이터 시각화를 위한 라이브러리로, 다양한 그래프와 차트를 만들 수 있게 해준다.
- plotly: 대화형 시각화가 가능한 그래프를 생성할 수 있는 라이브러리로, 웹 기반 시각화에 강점을 갖고 있다.
- pandas: 데이터 분석을 위한 라이브러리로, 데이터 조작 및 분석을 쉽게 할 수 있는 고성능 데이터 구조 제공.
- numpy: 고성능의 수치 계산을 위한 라이브러리로, 다차원 배열 객체와 다양한 수학 함수가 포함되어 있다.
- uvicorn: ASGI(Asynchronous Server Gateway Interface) 서버로, FastAPI와 같은 비동기 어플리케이션을 실행하기 위해 사용.
가상의 고객 데이터(더미 데이터) 생성하여
데이터베이스에 넣기
각 테이블별로 생성해야 하는 데이터 수는 다음과 같다.
- 고객 30명 생성 (customers 테이블)
- 상품 30개 생성 (products 테이블)
- 판매 1000건 생성 (sales 테이블)
- 결제 1000건 (판매와 연결) (payments 테이블)
- 리뷰 900건 (일부 판매된 상품에 연결) (reviews 테이블)
◆ 데이터베이스 연결하기 (PostgreSQL)
import psycopg2
import random
from faker import Faker
from datetime import datetime, timedelta
import string
# PostgreSQL 연결 정보
DB_NAME = "shop"
DB_USER = "postgres"
DB_PASSWORD = "1234"
DB_HOST = "localhost"
# Faker 라이브러리 사용
faker = Faker('ko_KR')
def connectd_db():
return psycopg2.connect(
dbname=DB_NAME, user=DB_USER, password=DB_PASSWORD, host=DB_HOST
)
- psycopg2는 PostgreSQL과 Python을 연결하는 데 필수적인 도구
◆ customers 테이블에 더미 데이터 생성해서 삽입하기
def insert_customers(cursor):
print("[1/5] 고객 데이터 생성 중...")
for _ in range(30):
# AUTO_INCREMENT (SERIAL) 생략 가능
cursor.execute(
"""
INSERT INTO customers (name, email, phone, gender, birth_date, registration_date, userid, passwd)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
""",
(faker.name()[:20], # 이름: 20자 제한
faker.email()[:50], # 이메일: 50자 제한
faker.phone_number()[:15], # 전화 번호 길이 제한
random.choice(["Male", "Female"]),
faker.date_of_birth(minimum_age=18, maximum_age=65),
faker.date_time_between(start_date="-2y", end_date="now"), # 현재 시간으로부터 2년 전
faker.user_name()[:10] + (str(random.randint(1,9999))), # userid : 이름과 임의의숫자 조합
faker.password()) # 비밀번호
)
◆ products 테이블에 더미 데이터 삽입하기
def insert_products(cursor):
print("[2/5] 상품 데이터 생성 중...")
for _ in range(30):
cursor.execute(
"""
INSERT INTO products (name, category, price, stock_quantity, created_at)
VALUES (%s, %s, %s, %s, %s)
""",
(faker.word(),
random.choice(["Electronics", "Clothing", "Books", "Furniture"]),
round(random.uniform(10, 1000), 2), # 10 ~ 100 사이의 무작위 가격 (소수점 2자리 수)
random.randint(10, 100),
faker.date_time_between(start_date="-2y", end_date="now"))
)
◆ sales 테이블에 더미 데이터 삽입하기
def insert_sales(cursor):
print("[3/5] 판매 데이터 생성 중...")
# customer_id만 조회하므로, 단일 컬럼 데이터 처리
# 리스트 컴프리헨션을 사용
cursor.execute("SELECT customer_id FROM customers")
customers = [row[0] for row in cursor.fetchall()] # fetchall의 결과는 리스트에 튜플 형태로 담겨옴 [(1, ), (2, )] > 0번째 값만 추출
cursor.execute("SELECT product_id, price FROM products")
products = cursor.fetchall() # 튜플이 들어있는 리스트 (product_id, 가격)
sales = []
for _ in range(1000):
customer_id = random.choice(customers)
product_id, price = random.choice(products) # products 튜플에 들어있는 값
quantity = random.randint(1, 5)
total_price = price * quantity
sale_date = faker.date_time_between(start_date="-2y", end_date="now")
sales.append((customer_id, product_id, price, total_price, sale_date))
cursor.executemany(
"""
INSERT INTO sales (customer_id, product_id, quantity, total_price, sale_date)
VALUES (%s, %s, %s, %s, %s)
""",
sales
)
- cursor.execute("SELECT customer_id FROM customers"): customers 테이블에서 customer_id 열의 모든 값을 선택.
※ cursor.execute(): SQL 쿼리를 실행하는 메서드. cursor는 데이터베이스의 명령을 실행하고 결과를 가져오는 객체 - customers = [row[0] for row in cursor.fetchall()]: fetchall() 메서드를 사용하여 SELECT 쿼리의 결과를 가져옴. 결과는 리스트 형태의 튜플로 반환
- products = cursor.fetchall(): 이 메서드는 이전 쿼리의 결과를 모두 가져와서 products라는 변수에 저장. 이 변수에는 각 제품의 product_id와 가격이 포함된 튜플이 들어있는 리스트가 저장 됨.
◆ payments 테이블에 더미 데이터 삽입하기
def insert_payment(cursor):
print("[4/5] 결제 데이터 생성 중...")
cursor.execute("SELECT sale_id FROM sales")
sales_id = [row[0] for row in cursor.fetchall()]
payments = []
for sale_id in sales_id: # 실제 판매된 데이터에만 생성되도록
payment_method = random.choice(["Credit Card", "PayPal", "Bank Transfer"])
payment_status = random.choice(["Completed", "Pending", "Failed"])
payment_date = faker.date_time_between(start_date="-1y", end_date="now")
payments.append((sale_id, payment_method, payment_status, payment_date))
cursor.executemany(
"""
INSERT INTO payments (sale_id, payment_method, payment_status, payment_date)
VALUES (%s, %s, %s, %s)
""",
payments
)
◆ reviews 테이블에 더미 데이터 삽입하기
def insert_reviews(cursor):
print("[5/5] 리뷰 데이터 생성 중...")
# 구매 건(sales)에 대한 리뷰가 아닌 구매 상품(products)에 대한 리뷰
cursor.execute("SELECT customer_id, product_id FROM sales ORDER BY RANDOM() LIMIT 900")
reviews = []
for customer_id, product_id in cursor.fetchall():
rating = random.randint(1,5)
review_text = faker.paragraph(nb_sentences=3, variable_nb_sentences=True)[:200] if random.random() > 0.2 else None # 20% 확률로 텍스트 없음
review_date = faker.date_time_between(start_date="-1y", end_date="now")
reviews.append((customer_id, product_id, rating, review_text, review_date))
cursor.executemany(
"""
INSERT INTO reviews (customer_id, product_id, rating, review_text, review_date)
VALUES (%s, %s, %s, %s, %s)
""",
reviews
)
◆ main 함수
def main():
conn = connectd_db()
cursor = conn.cursor()
insert_customers(cursor)
insert_products(cursor)
insert_sales(cursor)
insert_payment(cursor)
insert_reviews(cursor)
conn.commit()
cursor.close()
conn.close()
print("🤞🏻 더미 데이터 생성 완료!")
if __name__ == "__main__":
main()
더미데이터 생성이 완료되어 데이터베이스에 잘 삽입되었다.
근데 리뷰는 한글로 설정해도 라틴어(?)로 밖에 생성이 안 되나 보다.
[참고]
https://zephyrus1111.tistory.com/405
다음 내용
[FastAPI] FastAPI + Streamlit + PostgresSQL (2)
이전 내용 [FastAPI] FastAPI + Streamlit + PostgresSQL (1)이전 내용 [SQL] PostgreSQL: pg Admin 사용하기이전 내용 [SQL] PostgresSQL 다운로드 하기PostgresSQL 란? PostgreSQL은 오픈 소스 객체-관계형 데이터베이스 관리 시
puppy-foot-it.tistory.com