프로젝트 중 fk 때문에 발생한 에러를 수도 없이 봐왔지만, 이번 에러에선 특히 배울점이 매우 많다고 생각해서 포스팅해본다.
처음에 get_or_create() 를 보고 신세계라고 생각하고 편하게 쓰고 있던 중 갑자기 foreign key 에러가 발생했다.
에러명은 다음과 같은 식이였다.
FOREIGN KEY CONSTRAINT FAILS (5-8-2)
처음에 든 생각은,
라는 생각이였다.
그래서 한참을 헤매다가 그 이유를 알게되었다.
- 먼저 cart 에 상품을 담고, 이미 있는 상품이면 담았던 quantity 만큼 추가해주는 로직이였다.
- 그래서
product_id
,order_id
,product_option_id
,quantity
를 get_or_create() 의 인자로 넘겨줘서, 없으면 새로 row 를 만들고 있으면 quantity 만 추가하기로 했었다.
바로 여기서 문제가 시작된다.
product_id
, order_id
, product_option_id
, quantity
를 비교할것이다.product_id
, order_id
, product_option_id
세개의 값은 같지만 quantity
product_id
, order_id
, product_option_id
의 값이 unique 하게 묶여있었기 때문에 에러를 뱉는다.quantity
를 제외한 세 컬럼의 값을 models.py 에서 unique_together 로 묶어주었기 때문에 에러가 난것이다.
그렇다면 어떻게 해야 에러가 안날까 ?
답은 간단하다.
quantity 를 defaults 키값안에 딕셔너리 형태로 넘겨주면 된다.
cart, is_created = Cart.objects.get_or_create(
product_id = product_id,
order = order,
product_option_id = option['product_option_id']
defaults = {'quantity': option['product_option_quantity']}
이렇게 되면 defaults 값을 제외하고 검사한 뒤, 없으면 값을 defaults 에 입력된 값과 함께 생성하고 있으면 해당 row 를 가져온다.
다음은 다른 케이스에서 왜 fk constraint 에러가 났는지 디버깅하는 과정이다.
위에 get_or_create() 로 새로운 row 생성 시 발생한 에러들 처럼,
어떤 fk constraint 에러를 발생한 이유를 찾을 때 내가 디버깅하는 단계를
다른 케이스를 예시로 들어서 설명하려고 한다.
다음 에러메시지를 보자.
FOREIGN KEY ('product_option_id') REFERENCES 'product_options' ('id')
바로 이 부분인데, 여기서부터 디버깅을 시작하면 된다.
product_option_id
가 실제 product_options
테이블의 id 를 참조하려고 할 때 발생한 오류이다.product_option_id
가 23 번이였는데, 위 테이블에 id 가 23 번인 row 는 어딜 봐도 없다.product_option_id
를 임의로 집어넣는 과정에서 생긴 문제였다.