멋진 개발자가 되고 싶어

[django] foreign key null로 설정하며 발생한 에러 본문

PYTHON/Django

[django] foreign key null로 설정하며 발생한 에러

nutonny 2024. 1. 19. 13:53

2024년 1월 19일 새롭게 테이블을 생성하면서 발생한 에러를 정리해보았다.
생성하려는 테이블은 고객 테이블과 고객을 위한 사이트 테이블이었다.

on_delete=models.SET_NULL

  • 고객사는 있으나 사이트는 없을 수 있다고 생각하여 NULL이 가능한 FOREIGN KEY FIELD를 만들고 싶었다
  • 아래의 내용을 참조하여 적용해봤다.
    SET_NULL : ForeignKeyField 값을 NULL로 바꾼다. null=True일 때만 사용할 수 있다.
    test = models.ForeignKeyField(TestModel, on_delete=models.SET_NULL, null=True)
  • 위와 같이 입력하였으나 아래와 같은 오류 메시지가 발생했다.
    It is impossible to add a non-nullable field 'site_id' to site without specifying a default. This is because the
    database needs something to populate existing rows. 
    Please select a fix: 
    1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 
    2) Quit and manually define a default value in models.py. 
    Select an option: 1 
    Please enter the default value as valid Python. 
    The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as 
    a value. 
    Type 'exit' to exit this prompt 
    >>> None    
  • 아래의 내용을 참조하여 default값을 None으로 설정해주었다
  • 에러가 해결되었다.
django는 python 기반 웹 프레임워크이다.
python 에는 null이 없고 None이 있으며, 따라서 django에서도 default=null이라고 설정할 수 없다.
(python 에서는 None이 null에 대응하며, 타입은 NoneType이다.)

따라서, default=None, null=True 라고 설정해야 한다.

on_delete=models.PROTECT

  • 생각해보니 하나의 고객의 사이트가 여러 개 일 수 있다는 생각을 했다.
  • 그러니까 고객과 사이트는 일 대 다 관계여야한다.
  • 따라서 고객 테이블에 사이트의 아이디가 있을것이 아니라 사이트 테이블에 고객의 아이디를 참조할 수 있도록 해야한다.
  • 사이트를 삭제하는 경우 고객정보까지 삭제되면 안되므로 아래의 내용을 참고하여 설정을 바꾸었다.
PROTECT : 해당 요소가 같이 삭제되지 않도록 ProtectedError를 발생시킨다.
from django.db import models
class TestModel(models.Model):
    pass
class FKModel(models.Model):
    test = models.ForeignKeyField(TestModel, on_delete=models.PROTECT)
  • 처음에 null을 true로 하고 migrate해버려서 다시 Null을 False로 수정했다.
  • 그러자 발생한 에러는 이렇다.
    It is impossible to change a nullable field 'client_id' on site to non-nullable without providing a default. Thi
    s is because the database needs something to populate existing rows. 
    Please select a fix: 
    1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 
    2) Ignore for now. Existing rows that contain NULL values will have to be handled manually, for example with a 
    RunPython or RunSQL operation. 
    3) Quit and manually define a default value in models.py. 
    Select an option: 3
  • default 값을 설정해주면 된다고 한다.
  • 이번엔 직접 파일로 접근해 수정하고 싶어 3번 옵션을 선택하였다.
  • 이후 models.py에 들어가 default=''로 설정해주었다.
  • 다시 migrate하니 더이상 에러 메시지가 뜨지 않았다.

참고 자료

[Django] Django 모델 ForeignKeyField on_delete 종류
[django] null과 blank

Comments