#13 데이터베이스 연결

#13 데이터베이스 연결

프로그램상에서 작성한 문서의 데이터는 로컬 데이터베이스에 저장하여 관리할 것이다. 그러기 위해서는

먼저 DBMS(DataBase Management System)를 설치해야한다. 여기서는 PostreSQL 을 사용할 것이다.

1. PostgreSQL 설치

먼저 PostgreSQL 공식 홈페이지에 접속하여 Download 페이지로 들어간다.

윈도우 환경에 설치할 것이기 때문에 Windows 를 선택한다.

Download the installer 를 클릭하고 운영체제에 맞는 최신버전을 다운로드한다. 다운로드 받은 설치파일을

실행하고 next를 눌러 설치를 진행하다보면 데이터베이스의 슈퍼유저(postgres) 계정을 생성하기 위해 암호를

입력받는다. 이후에 별도로 건드릴 것은 없으니 계속 next를 눌러 설치를 마친다.

2. 데이터베이스 서버 생성

PostgreSQL을 설치했으니 이제 데이터를 저장할 DB 서버를 생성해야한다. 위의 설치과정에서 자동으로

설치됐을 PostgreSQL의 GUI툴인 pgAdmin 을 실행하여 위와 같이 server 를 우클릭하여 새 서버를 생성한다.

pgAdmin 실행시 요구하는 암호는 PostgreSQL 설치시에 입력한 슈퍼유저 계정의 암호를 입력해주면 된다.

먼저 General 탭의 Name 에는 서버의 이름을 입력해준다. 무엇으로 하든 상관없으니 원하는 이름을 입력한다.

Connection 탭에서는 호스트 이름 혹은 주소, 포트번호, 유저명, 패스워드를 입력한다. 로컬 DB로 사용할 것이기

때문에 호스트는 localhost로 해주고 포트번호는 PostgreSQL의 기본 포트번호인 5432를 그대로 사용한다.

유저명과 패스워드는 DB를 사용할 계정의 것을 입력해야한다. 여기서는 슈퍼유저 계정인 postgres를 사용한다.

모두 입력한 뒤 save를 누르면 서버가 생성된 것을 볼 수 있다.

3. sqlAlchemy 설치

sqlAlchemy는 Python에서 데이터베이스를 다루기 위한 SQL 툴킷이며 ORM(Object Relational Mapper)이다.

ORM은 데이터베이스의 데이터들을 객체의 형태로 매핑해주는 것으로 사용자가 SQL문에 의존하지 않고

객체지향적인 코드로 DB를 다룰 수 있게 해준다. sqlAlchemy 는 현재 Python 웹 프레임워크인 Flask에서도

사용되고있으며 마찬가지로 Python 웹 프레임워크인 Django 의 ORM과 함께 Python에서 가장 널리 사용되는

ORM 툴이다. 여기서는 sqlAlchemy 를 사용하여 애플리케이션을 DB와 연결해본다.

pip install sqlalchemy

설치는 매우 간단하다. 현재 개발환경인 Pycharm의 Terminal은 기본적으로 가상환경에 진입한 상태이기 때문에

터미널상에서 바로 pip 명령어를 사용하여 설치해주면 된다.

4. db_manager.py

import json from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session, sessionmaker # 데이터베이스 패스워드를 저장한 secrete_file.json 을 읽는다 with open('secrete_file.json') as f: secretes = json.loads(f.read()) # postgresql 의 형식에 따라 엔진 생성 engine = create_engine('postgresql://{username}:{db_password}@{host}:{port}/{db_name}'.format( username='postgres', db_password=secretes['db_password'], host='localhost', port='5432', db_name='postgres' )) # DB 세션 생성 session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) # 모델 매핑 Base = declarative_base() Base.query = session.query_property() # db 초기화 def init_db(): Base.metadata.create_all(engine)

controller 디렉토리에 db_manager.py 를 위와 같이 작성

secrete_file.json 에서 데이터베이스의 패스워드를 읽음

create_engine 에 postgresql의 형식에 맞춰 정보를 입력해주는 것으로 엔진을 생성

sessionmaker와 scoped_session 을 사용하여 엔진과 연결된 세션을 생성 autocommit과 autoflush를 False 로 하는 것은 여러개의 쿼리문을 적용해야할 때 한번에 commit을

실행하기 위해서이다.(flush가 발생하면 db에 실제로 삽입, 삭제 등의 연산을 수행한 상태가 된다.

다만 commit까지는 가지 않는다. commit은 내부적으로 flush를 먼저 수행한다.)

declarative_base 를 사용하여 Base를 상속하여 선언한 클래스(모델)들을 매핑해준다.

init_db를 호출하면 연결된 db에 선언한 모델들을 기반으로 테이블을 생성한다.

5. 모델 선언

from sqlalchemy import Column, Integer, String, DateTime from controller.db_manager import Base # 화주 모델 class DayCalOwner(Base): __tablename__ = 'daycal_owner' name = Column(String, primary_key=True) def __init__(self, name): self.name = name # 화주별 일일정산 데이터 모델 class DayCalOwnerValues(Base): __tablename__ = 'daycal_owner_values' datetime = Column(DateTime, primary_key=True) owner_name = Column(String, primary_key=True) kd_total = Column(Integer) kd_fare = Column(Integer) kd_drop = Column(Integer) match_fee5 = Column(Integer) owner_fare = Column(Integer) owner_drop = Column(Integer) listing_fee4 = Column(Integer) kd_pre = Column(Integer) def __init__(self, datetime, owner): self.datetime = datetime self.owner = owner # 일일정산서에 입력될 기타 데이터 모델 class DayCalOtherValues(Base): __tablename__ = 'daycal_other_values' datetime = Column(DateTime, primary_key=True) office_deposit = Column(Integer) kd_deposit = Column(Integer) direct_exp = Column(Integer) our_auc = Column(Integer) kd_buy = Column(Integer) def __init__(self, datetime): self.datetime = datetime

model 디렉토리의 models.py에 일일정산서에 필요한 모델들을 선언

모델 클래스는 모두 Base 를 상속

6. DB 초기화

from PySide6.QtWidgets import QTabWidget, QWidget, QTableWidget, QGridLayout from controller.db_manager import session, init_db from models.models import DayCalOwner # 일일 정산서 계산서 위젯 class DayCal(QWidget): # 생성자 def __init__(self): super().__init__() self.init_ui() # ui 초기화 def init_ui(self): init_db() # 화주 목록 owners = [q.name for q in session.query(DayCalOwner)] input_table = QTableWidget() input_table.setColumnCount(len(owners)) input_table.setHorizontalHeaderLabels(owners) input_table.setRowCount(19) input_table.setVerticalHeaderLabels([ '강동총금액', '강동운임', '강동하차비', '강동수수료 4%', '공제후금액', '', '중매수수료 5%', '화주운임', '화주하차비', '상장수수료 4%', '강동선지급금', '공제합계', '선지급금포함 공제합계', '', '경매 사무실입금', '가라경매 강동입금', '직접지출', '우리경매', '강동사입' ]) # 그리드 레이아웃 grid = QGridLayout() # 테이블위젯 추가 grid.addWidget(input_table, 0, 0) # 레이아웃 세팅 self.setLayout(grid)

이 작업은 DB 세팅시에 한번만 수행해주면 된다. 원래라면 이 세팅은 별도의 파일로 분리해야하지만 여기서는

우선 테스트를 위해 DB를 처음 사용할 DayCal 위젯의 init_ui에서 init_db 함수를 실행하여 수행해주자. 그리고

이전에는 임시로 화주1, 화주2, 화주3을 넣어주었던 owners를 DB 세션에서 query를 통해 DayCalOwner,

즉 화주 데이터를 가져온 후 그 이름으로 이루어진 리스트를 구성한다. 이제 column 의 헤더 레이블은 DB에

등록된 화주명단에 기반하여 붙여질 것이다.

그런데 위의 작업가지 완료한 후 애플리케이션으 구동해보면 위와 같이 column이 아예 없어진 것을 볼 수 있다.

테이블만 생성했을 뿐 추가된 화주가 하나도 없기 때문이다. 다음 포스팅에서는 화주 추가/삭제 기능을 구현하여

실제로 데이터베이스에 등록된 화주 리스트에 따라 표가 나타나도록 해본다.

from http://scala0114.tistory.com/149 by ccl(A) rewrite - 2021-10-30 21:26:40