[Django] OneToOneField Error

즐겁고치열하게·2022년 11월 23일
0
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'))

django에서 signals.py 생성 시 설정
[Django] post_save()는 뭐야?

profile
기술을 공부하는 기술자

0개의 댓글