3-09 글쓴이 저장하기

회원가입, 로그인, 로그아웃 기능이 완성되어 질문, 답변을 "누가" 작성했는지 알 수 있게 되었다. 이제 기능을 조금씩 다듬어서 파이보를 완벽하게 만들어 보자. 여기서는 Question, Answer 모델을 수정하여 "글쓴이"에 해당하는 user 속성을 추가할 것이다.

데이터베이스 설정 수정하기

SQLite 데이터베이스는 ORM을 사용할 때 몇 가지 문제점이 있다. 이것은 SQLite 데이터베이스에만 해당하고 PostgreSQL이나 MySQL 등의 다른 데이터베이스와는 상관없는 내용이다. 앞으로의 진행을 원활하게 하기 위해 SQLite가 발생시킬 수 있는 오류를 먼저 해결하고 넘어가자.

[파일명: projects/myapi/database.py]

from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

(... 생략 ...)

Base = declarative_base()
naming_convention = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(column_0_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}
Base.metadata = MetaData(naming_convention=naming_convention)

(... 생략 ...)

MetaData 클래스를 사용하여 데이터베이스의 프라이머리 키, 유니크 키, 인덱스 키 등의 이름 규칙을 새롭게 정의했다. 데이터베이스에서 디폴트 값으로 명명되던 프라이머리 키, 유니크 키 등의 제약조건 이름을 수동으로 설정한 것

그리고 migrations 디렉터리의 env.py 파일도 다음과 같이 수정해야 한다.

[파일명: projects/myapi/migrations/env.py]

(... 생략 ...)

def run_migrations_offline() -> None:
   (... 생략 ...)
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
        render_as_batch=True,
    )

    (... 생략 ...)

def run_migrations_online() -> None:
    (... 생략 ...)
    with connectable.connect() as connection:
        context.configure(
            connection=connection,
            target_metadata=target_metadata,
            render_as_batch=True,
        )

        (... 생략 ...)

ontext.configure 설정에 render_as_batch=True 설정을 추가했다.

이와 같이 수정한 후에 alembic revision --autogenerate 명령과 alembic upgrade head 명령으로 데이터베이스를 변경해야 한다.

(myapi) c:/projects/myapi> alembic revision --autogenerate
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added unique constraint 'uq_user_email' on '['email']'
INFO  [alembic.autogenerate.compare] Detected added unique constraint 'uq_user_username' on '['username']'
  Generating /Users/pahkey/projects/myapi/migrations/versions/f77ce8f209c6_.py ...  done
(myapi) c:/projects/myapi> alembic upgrade head          
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade 87416c9d163d -> f77ce8f209c6, empty message

혹시 이 과정에서 오류가 발생할 경우에는 alembic stamp head 명령을 실행한 후에 다시 위의 과정을 반복

Question 모델에 글쓴이 추가하기

다음과 같이 글쓴이 정보를 Question 모델에 추가하기 위해 user_id, user 속성을 추가

[파일명: projects/myapi/models.py]

(... 생략 ...)

class Question(Base):
    __tablename__ = "question"

    id = Column(Integer, primary_key=True)
    subject = Column(String, nullable=False)
    content = Column(Text, nullable=False)
    create_date = Column(DateTime, nullable=False)
    user_id = Column(Integer, ForeignKey("user.id"), nullable=True) #연결
    user = relationship("User", backref="question_users") #참조

(... 생략 ...)

user_id 속성은 User 모델을 Question 모델과 연결하기 위한 속성이고 user 속성은 Question 모델에서 User 모델을 참조하기 위한 속성이다. ForeignKey와 relationship은 질문과 답변 모델을 연결하는 부분에서 다루었으므로 자세한 설명은 생략한다.