ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Foreign Key - CASCADE
    Django 2021. 12. 16. 17:51

    Foreign Key

     - 한 테이블을 다른 테이블과 연결 (1:N 관계)

     - 참조되는 테이블의 필드(1:N에서 1이 되는 테이블)는 반드시 UNIQUE나 PRIMARY KEY 제약 조건 설정

     - 2개의 인자 필요(대상이 되는 클래스, 대상이 되는 클래스 삭제시 조건)

     - 참조되는 테이블의 데이터 수정이나 삭제가 발생하면, 참조하고 있는 테이블의 데이터도 같이 영향을 받습니다.

     - ex) 게시글 - 댓글

     

    이때 참조하고 있는 테이블의 동작은 다음 키워드를 사용하여 FOREIGN KEY 제약 조건에서 미리 설정할 수 있습니다.

     

    1. ON_DELETE (참조되는 테이블의 값이 삭제되는 경우)

    2. ON_UPDATE (참조되는 테이블의 값이 수정되는 경우)

     

    외래 키가 설정된 테이블에 레코드를 입력하면, 기준이 되는 테이블의 내용을 참조해서 레코드가 입력됩니다.

    즉, FOREIGN KEY 제약 조건은 하나의 테이블을 다른 테이블에 의존하게 만듭니다.

     

     

    # CASCADE : 상위 테이블의 데이터 삭제 시 하위 테이블의 데이터도 삭제


    # Set_null : 상위 테이블의 데이터 삭제 시 하위 테이블의 참조 컬럼을 Null로 업데이트

                       (null=True 옵션이 있어야만 가능하다) 유저 탈퇴시 댓글의 작성자가 익명 처리된다.


    #Set default : 상위 테이블의 데이터 삭제 시 하위 테이블의 참조 컬럼을 Default 값으로 업데이트

                           (default=True 옵션이 있어야만 가능하다)

     

    #Restrict : 하위 테이블이 참조하고 있을 경우 데이터 삭제 불가

     

    #PROTECT : 상위 테이블의 데이터 삭제 시 하위 테이블의 데이터가 삭제 되지 않도록 ProtectedError 발생시킴

                         (삭제하려면 참조하는 모든 객체를 수동으로 삭제해야 함)

     

    #NO ACTION : 참조되는 테이블에서 데이터를 삭제하거나 수정해도, 

                            참조하는 테이블의 데이터는 변경되지 않습니다.

     

    • N -> 1 접근 : 하위 테이블명.상위 테이블명
    • 1 -> N 접근 : 상위 테이블명.하위 테이블명_set

    models.py 예시

    1 : N 관계 (Owner : Dog)

    Dogs 테이블이 Owners 테이블을 참조하게 하고 있으며 on_delete=models.CASCADE 를 통해서 Owner 데이터가 삭제될 경우 연결된 Dog 데이터도 함께 삭제된다는 의미입니다.

     

    제가 입력한 owners, dogs 테이블의 데이터입니다.

     

    여기서 만약 삭제하고자 한다면 제가 찾은 방법은 2가지입니다.

     

    1. shell에서 삭제하는 방법

    2. Mysql에서 직접 삭제하는 방법

     

    1. shell에서 삭제하는 방법

    Shell에서 Foreign Key로 연결된 상위테이블 데이터 삭제하는 예시

    >>> a = Owners.objects.filter(id=3)

    a가 QuerySet(전달받은 모델의 객체 목록)이어서 a.name으로는 a의 이름을 가져올 수 없습니다.

    그래서 a[0].name 을 통해서 데이터를 잘 불러왔단 것을 확인할 수 있었습니다.

    # a[1].name을 하면 IndexError: list index out of range 라고 뜨는 것을 확인하실 수 있을 것입니다.

    >>> a[0].delete()

    >>> (2, {'owners.Dogs: 1, 'owners.Owners': 1})

    owners와 dogs 테이블에서 Foreign Key로 연결되어 있던 데이터가 1개씩 지워졌다는 것을 보여줍니다.

    아래의 Mysql 테이블을 보시면 방금 지운 데이터가 삭제된것을 보실 수 있습니다.

    owners 테이블의 id=3인 데이터 삭제 후 모습

    2. Mysql에서 직접 삭제하는 방법

    owners 테이블에 있는 id 값이 2인 데이터를 삭제하려고 했더니 아래와 같은 에러 메세지가 뜹니다.

    ERROR 1451 - 삭제하려고 하는 행이 다른 곳에서 참조하고 있어서 발생하는 에러
    Foreign Key 설정 변경 후 데이터 삭제

    Mysql에서 SET FOREIGN_KEY_CHECKS=0; 이라고 입력하면 Foreign Key의 CASCADE 효과가 없어집니다.

    이후 delete from owners where id=2; 라고 입력하면 삭제되었다는 메세지를 보실 수 있습니다.

    owners 테이블의 id=2인 데이터 삭제했으나 Foreign Key로 연결된 dogs 테이블의 데이터들은 그대로 있는 것을 확인하실 수 있습니다.

    그래서 CASCADE로 설정되어 있음에도 불구하고 Mysql에서 데이터를 삭제하시려면

    SET FOREIGN_KEY_CHECKS 를 바꿔주시고 관련 데이터들을 모두 직접 삭제해주셔야 합니다.

    그 후에 SET FOREIGN_KEY_CHECKS=1; 로 바꾸신 후에 테이블을 보시면 확인이 가능합니다.

     

    결론

    CASCADE로 설정했는데 연결된 데이터를 삭제하셔야 한다면

    1. 연결된 데이터 모두 삭제를 원하신다면

        SHELL에서 인스턴스에 원하는 데이터를 담아서 delete 하시면 됩니다.

    2. 그게 아니라 일부 데이터만 삭제를 원하신다면

        Mysql에서 CASCADE 설정을 잠시 바꾸신 후 직접 삭제하시는 방법이 있습니다.

    댓글

Designed by Tistory.