reverse와 reverse_lazy의 차이
Django의 초기화 읽는 순서는 아래와 같습니다. 물론 실제 초기화는 더 복잡하지만 여기 3개 파일만 놓고 봤을 때 이 순서로 초기화가 됩니다.
- models.py
- views.py
- urls.py
reverse()는 URL을 name으로 읽어오는 함수입니다. 3번까지 모두 읽어야 name을 읽어올 수 있습니다. 그런데 클래스 내부에서 클래스 변수로 reverse()를 사용하면 2번까지만 읽어온 상태에서 reverse()를 사용하게 됩니다. 아래 코드를 실행해보세요.
class MyClass:
class_var = 10
print("클래스 정의 중") # 클래스 정의 시 즉시 실행됨
class_sum = sum([1, 2, 3])
print("클래스 정의 완료")
print(MyClass.__dict__) # 클래스의 네임스페이스 확인
print(MyClass.class_sum) # 클래스 변수에 접근
class MyClass:
class_var = 10
print("클래스 정의 중") # 클래스 정의 시 즉시 실행됨
class_sum = sum([1, 2, 3])
print("클래스 정의 완료")
print(MyClass.__dict__) # 클래스의 네임스페이스 확인
print(MyClass.class_sum) # 클래스 변수에 접근
이처럼 클래스 바로 아래 선언된 코드는 클래스가 정의되는 시점에 실행됩니다.
class PostCreate(LoginRequiredMixin, CreateView):
model = Post
fields = ["title", "content", "head_image", "file_upload"]
success_url = reverse_lazy("blog_list")
class PostCreate(LoginRequiredMixin, CreateView):
model = Post
fields = ["title", "content", "head_image", "file_upload"]
success_url = reverse_lazy("blog_list")
그래서 위 코드에서 reverse()를 사용하면 안되는 것입니다. 아직 URL을 읽어오지 않았기 때문입니다. 아래 코드도 실행해볼 수 있습니다.
def test(request):
# reverse()와 reverse_lazy()의 차이
print(reverse_lazy("blog_list")) # /blog/
print(reverse("blog_list")) # /blog/
return HttpResponse("test")
def test(request):
# reverse()와 reverse_lazy()의 차이
print(reverse_lazy("blog_list")) # /blog/
print(reverse("blog_list")) # /blog/
return HttpResponse("test")
여기서 views.py에 test함수 내에 reverse가 있으므로 애러가 날 것 같지만 애러가 나지 않습니다. 이유는 파이썬이 함수를 읽을 때에는 내부 코드까지 읽지 않고 test라는 이름만 등록하고 넘어가기 때문입니다. Django입장에서는 test라는 이름이 등록되고, URL을 읽는 3번으로 넘어가는 것이죠. 실제로 구동이 될 때에는 둘 다 정상적으로 실행이 됩니다. 이미 초기화가 되었기 때문입니다.
그렇기에 CBV에서는 '지연'이 필요합니다. 실제 이 URL이 필요할 때까지 미루는 것이죠. 그렇지만 항상 지연시킬 필요는 없습니다. 파이썬에서 클래스 바로 아래 선언된 코드는 클래스가 정의되는 시점에 실행이 되지만, 클래스 안에 메서드는 함수처럼 이름만 등록을 하죠. 그렇기에 클래스 변수로 reverse()를 사용하면 안되지만 클래스 안에 메서드로 선언해서 사용하면 사용이 가능합니다. 이러한 원리로 redirect로 한 번 reverse를 감싸주는 것도 사용이 가능합니다.
실제 reverse_lazy 구현은 reverse_lazy = lazy(reverse, str)
로 되어 있습니다.