django.db.utils.IntegrityError: NOT NULL constraint failed: ML_evaluation.ml_model_id
django.db.utils.IntegrityError: NOT NULL constraint failed: {app이름}_{대상 클래스명: Profile}.{상위 클래스명: User}_id
보통 인터넷에서 질문하는 User-Profile관계를 ML_Model-Evaluation 클래스로 구현하다 발생했던 문제이다.
Test코드를 작성하던 중 OneToOneFiled를 검증하기 위해 form.save()를 호출 했을 때 계속 오류가 생겼다.
해당 문제는 ModelForm으로 받아온 데이터를 Evaluation(보통 인터넷 예제들은 Profile)에 넣어 Create할 때 제대로 Create되지 않아서 발생한 문제였다.
문제 코드
def test_create_evaluation(self):
my_model = ML_Model.objects.get(pk=1)
eval_data = {
'ml_model': my_model
'total': 10,
'success': 2,
}
print(eval_data)
form = EvaluationForm(data=eval_data, instance=my_model)
form.save()
print(my_model.evaluation)
self.assertTrue(form.is_valid())
첫 번째, 해결 방법으로는 ml_model을 생성, get한 후 Evaluation.objects.create(ml_model=my_model) 후
EvaluationForm(data=form_data, instance=ml_model)
을 통해 해결 가능하다.
해결 코드
def test_create_evaluation(self):
my_model = ML_Model.objects.get(pk=1)
my_eval = Evaluation.objects.create(ml_model=my_model)
eval_data = {
'total': 10,
'success': 2,
}
print(eval_data)
form = EvaluationForm(data=eval_data, instance=my_eval)
form.save()
print(my_model.evaluation)
self.assertTrue(form.is_valid())
두 번째, form.save()를 사용시 발생하는 여러 signal 중에서 post_save 신호를 사용한다.
이 때 django.dispatch에서 제공하는 @receiver 데코레이터를 사용한다
signals.py 파일
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import ML_Model, Evaluation
@receiver(post_save, sender=ML_Model)
def create_model(sender, instance, created, **kwargs):
if created:
Evaluation.objects.create(ml_model=instance)
apps.py 파일
from django.apps import AppConfig
class MlConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'ML'
def ready(self):
# TODO: Write your codes to run on startup
import ML.signals
아래와 같이 추가하면 ML_Model을 대상으로 db에 save 후 post_save 신호가 발생해서 create_model이 작동한다.
signals.py는 아래와 같이 사용할 수도 있다.
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import ML_Model, Evaluation
@receiver(post_save, sender=ML_Model)
def create_model(sender, **kwargs):
if kwargs.get('created'):
Evaluation.objects.create(ml_model=kwargs.get('instance'))