코딩 하는 가든

Django - circular dependency 문제 (feat. cannot import name 'model') 본문

Django

Django - circular dependency 문제 (feat. cannot import name 'model')

가든리 2020. 3. 16. 15:07

Circular Dependency

 circular dependency는 순수 해석 그대로 circular(순환) dependency(의존성) 때문에 생기는 문제이다.

 

그럼 의존성이란 무엇인가?

예를 들어 A.py 라는 소스가 필요에 의해 B.py의 소스를 import 해 왔다고 치자 그렇다면 A 는 B에 의존성이 걸려 버린 것이다. 간단히 나타내면 A - > B 처럼 볼 수도 있겠다. 이어서 B.pyC.py를 import 할 수 있다. 이처럼 A -> B -> C - > D -> ...

이런 식으로 각 소스간의 의존성을 나타 낼 수 있는데 이렇게 주욱 늘어지다가 dependency가 최초에 dependency를 건 A로 되돌아 오면 다음과 같은 그림이 완성 된다.

 Django는 실행시 파이썬 코드를 한줄 한줄 읽어가며 필요한 소스를 import 해온다. A라는 파일에서 import B를 만나면 B로 가서 소스를 읽고, import C를 만나면 C로 가서 소스를 읽는 형식이다. 이럴 때, 위와 같은 A - > B -> C - > D - > A 같은 의존성이 생겨버리면 Django는 파일 import 를 무한히 반복하게 되어 결국 ImportError: cannot import name '~~~' 같은 에러를 낼 것이다.

 

Django에서의 간단한 예시를 통해 알아보자. Django 에서는 이러한 circular dependency가 모델간의 foriengkey 관계에서 자주 일어나는데

from django.db import models
from professor import Professor


class Student(models.Model):
    professor = models.Foreingkey(Professor, on_delete=models.CASCADE, help_text="담당교수")
    ~~~
    ~~~

 

from django.db import models
from student import Student


class Professor(models.Model):
    student = models.Foreingkey(Student, on_delete=models.CASCADE, help_text="담당학생")
    ~~~
    ~~~

위의 두 모델은 서로를 import 해오려고 하기 때문에 에러를 낼 것이다.

 

이를 해결 하려면 다음과 같이 Foreingkey 필드의 모델 부분에 'app_name.Model_name'을 적어주면 해당 model을 runtime에 필요시에 임포트 해 오기 때문에 오류를 띄우지 않을 것이다,

from django.db import models


class Student(models.Model):
    professor = models.Foreingkey('professor.Professor', on_delete=models.CASCADE, help_text="담당교수")
    ~~~
    ~~~
from django.db import models


class Professor(models.Model):
    student = models.Foreingkey('student.Student', on_delete=models.CASCADE, help_text="담당학생")
    ~~~
    ~~~

 

그렇기 때문에 Foreingkey를 사용할 때에는 'app.Model'로 임포트 해오는 것을 습관화 하자. 당장에는 문제가 발생하지 않더라도 프로젝트의 규모가 커지고 앱이 많아지다보면 언제 어디에서 circular dependency가 발생할지 모른다.