CASCADE 적용안되는것 질문이있습니다.

우선 좋은강의 감사드립니다!
알려주신 방법대로 따라서 하고있다가
"3-15 검색과 정렬" 부분을 실습하던중
제 결과물기준으로

Answer.query.count()

14

Question.query.count()

300

 Question.query.join(Answer).count()

10

이렇게 나왔습니다. 그래서 DB Browser를 실행해서 테이블을 봤는데
Answer 테이블에 question_id 부분에 Null 값들이 들어가있는것들을 발견했습니다.

Null이 어디서 생겼는지 생각해보니 "3-10 수정과 삭제" 부분에서 실습을할때 질문을 삭제를 했었습니다.
삭제를 할때 답변을 달려있는 질문도 삭제하였는데 여기서 문제가 발생한것같습니다.

Answer 모델설정할때 question_id 부분에 외래키 설정후 속성값으로

question_id = db.Column(db.Integer, db.ForeignKey('question.id', ondelete='CASCADE'))

ondelete = "CASCADE" 가 적혀있는데도 불구하고
질문이 삭제되어도 답볍은 question_id가 Null로만 변경이되고 삭제는 되지않았습니다.

그래서 SQL 문을 직접 입력하여 질문을 하나 삭제해보았는데
DB에서 직접삭제할때는 CASCADE 가 잘적용이되어 답변도 함께 삭제되었습니다.

python 내에서 db연결에 문제인지 설정중에 뭐가 빠진부분이있는지 감도 안오고

계속 찾다가 못발견해서 여쭤보려고 글을남깁니다 ㅠㅠ

답변주시면 감사하겠습니다.

__init__.py

from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy import MetaData

import config
from flaskext.markdown import Markdown

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"
}
db = SQLAlchemy(metadata=MetaData(naming_convention=naming_convention))
migrate = Migrate()

# db = SQLAlchemy()
# migrate = Migrate()


def create_app():
    app = Flask(__name__)

    app.config.from_object(config)

    # ORM
    db.init_app(app)

    if app.config['SQLALCHEMY_DATABASE_URI'].startswith('sqlite'):
        migrate.init_app(app, db, render_as_batch=True)
    else:
        migrate.init_app(app, db)


    from . import models
    # 블루프린트
    from .views import main_view,question_views,answer_views,auth_views,comment_views,vote_views
    app.register_blueprint(main_view.bp)
    app.register_blueprint(question_views.bp)
    app.register_blueprint(answer_views.bp)
    app.register_blueprint(auth_views.bp)
    app.register_blueprint(comment_views.bp)
    app.register_blueprint(vote_views.bp)

    # 필터
    from .filter import format_datetime
    app.jinja_env.filters['datetime'] = format_datetime

    # markdown
    Markdown(app, extensions=['nl2br','fenced_code'])


    return app

이동기 1768

M 2020년 9월 18일 11:09 오후

목록으로
1개의 답변이 있습니다. 1 / 1 Page

안녕하세요.

우선 좋은 질문 감사드립니다.
저도 당연히 될줄 알던것인데 테스트해 보니
질문을 삭제했을때 그에 달린 답변이 삭제가 안되고 question_id 만 Null 로 변경되는 현상을 경험했습니다.

연결된 답변 데이터가 delete가 아닌 update가 실행되는 것 같네요.

하지만 다음처럼 수정하니 update가 아닌 delete가 동작합니다.

class Answer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    question_id = db.Column(db.Integer, db.ForeignKey('question.id', ondelete='CASCADE'))
    question = db.relationship('Question', backref=db.backref('answer_set', cascade='delete'))
    content = db.Column(db.Text(), nullable=False)
    create_date = db.Column(db.DateTime(), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), nullable=False)
    user = db.relationship('User', backref=db.backref('answer_set'))
    modify_date = db.Column(db.DateTime(), nullable=True)

보시면 다음처럼 db.backref 안에 cascade라는 속성을 'delete'로 한번 더 지정해 주면 의도했던데로 답변데이터도 모두 삭제됩니다.

question = db.relationship('Question', backref=db.backref('answer_set', cascade='delete'))

우선 db.ForeignKey('question.id', ondelete='CASCADE')) 에 연결된 CASCADE 는 다음과 같은 테이블 생성 스크립트를 만들어 내는 역할을 합니다.

CREATE TABLE "answer" (
    id INTEGER NOT NULL, 
    question_id INTEGER, 
    content TEXT NOT NULL, 
    create_date DATETIME NOT NULL, 
    user_id INTEGER DEFAULT '1' NOT NULL, modify_date DATETIME, 
    PRIMARY KEY (id), 
    CONSTRAINT fk_answer_user_id_user FOREIGN KEY(user_id) REFERENCES user (id) ON DELETE CASCADE, 
    FOREIGN KEY(question_id) REFERENCES question (id) ON DELETE CASCADE
)

이러한 이유로 쿼리로 직접 삭제할 때는 답변이 함께 삭제되었습니다.

다만, 모델로 삭제할 경우에는 위처럼 수정해 주어야만 제대로 동작하네요.
"점프 투 플라스크"의 내용도 좀 수정이 되어야 겠습니다.

감사합니다.

박응용

2020년 9월 19일 12:06 오전

감사합니다ㅎㅎ - 이동기님, 2020년 9월 20일 12:51 오전 추천 , 대댓글