[Django] view에서 template에 동적으로 데이터 전송하기 - MVT패턴의 통신방식

느려도 꾸준한 발걸음·2024년 6월 20일
0

Django Web dev

목록 보기
3/12

장고의 views.py에는 템플릿(페이지를 만드는 html파일들)을 렌더링하는 함수들을 작성합니다.

아래는 프리미엄 회원만 볼 수 있는 페이지를 렌더링하도록 하는 view내의 함수입니다.

from django.shortcuts import render

def premium_page_loader(request):
	return render(request, 'premium_page.html', {'user_name': 'lee', 'user_age': '30'}

장고에서 제공하는 render함수의 세 번째 인자로 우린 데이터를 전송할 수 있고,
템플릿에서(이 경우는 premium_page.html이 되겠습니다) 이를 DTL로 받아 사용할 수 있죠.

<h1>{{user_name}}님의 {{user_age}}번째 생일을 축하합니다!</h1>

만일 다음과 같이 view에서 전달한 데이터를 받아온다면,
이 경우 브라우저엔 "lee님의 30번째 생일을 축하합니다!" 라는 문구가 나오게 됩니다.

물론 지금도 동적으로 데이터를 주고 받고 있다고 볼 수 있지만,
향후 비즈니스 로직이 복잡해질 경우, 이렇게 일일이 render함수에 객체 형태로 데이터를 직접 넣어주는 것은 코드의 가독성을 저하시키고, 많은 실수를 야기할 수 있습니다.

회원이 10명만 되어도 개발자가 일일이 회원 정보를 손으로 치고 있자면,
정말 비효율적인 상황이죠.

그래서 우리는 다음과 같은 솔루션을 도입해보겠습니다

models.py 파일에 클래스로 데이터의 틀을 정해두고,
views.py에서 인스턴스를 생성해 render의 세 번째 인자에는 직접 객체를 생성해 전달하는 것이 아닌, 인스턴스를 전달하겠습니다.

models.py 파일에 클래스 정의하기

데이터의 형태는 models.py에 클래스로서 정의해두고,
인스턴스의 생성은 views.py에서 하겠습니다.

위에서 살펴본 프리미엄 회원의 예제를 계속 사용하겠습니다.
저는 프리미엄 구독제를 가입한 회원들의 정보를 담아둘 클래스 PremiumMembers를 models.py 파일 안에 생성하겠습니다.

다음은 models.py파일의 모습입니다.

class PremiumMembers:
	user_name: str,
    user_age: int,

지금은 비즈니스 로직을 구현하는 것이 아니라,
장고 프레임워크에서 MVT요소간의 통신을 이해하려는 것이니, 생성자를 위시한 모든 복잡한 요소들은 배제하고, 최대한 간결하게 예제를 구성하겠습니다.

이제, 프리미엄 회원들의 정보는 문자열인 user_name과 정수값인 user_age이렇게 두 개의 프로퍼티를 갖습니다.

데이터의 형태를 정의하는 것으로 MVT중 M을 담당하는 models.py의 역할은 끝났습니다.

views.py파일에서 인스턴스 생성하기

이제 인스턴스를 생성해야 합니다.
인스턴스 생성은 models.py가 아니라, views.py파일 내에서 해줍니다.

아래는 변경 전의 views.py파일입니다.

from django.shortcuts import render

def premium_page_loader(request):
	return render(request, 'premium_page.html', {'user_name': 'lee', 'user_age': '30'}

이제 render함수의 세 번째 전달 요소에, 직접 값을 입력하지 않고,
따로 생성해둔 인스턴스를 전달하도록 하겠습니다.

from django.shortcuts import render
from .premium_members import PremiumMembers #models.py에 만들어둔 클래스 불러오기


def premium_page_loader(request):
	member1 = PremiumMembers()
    member1.user_name = 'lee'
    member1.user_age = 30

	return render(request, 'premium_page.html', {'member_A': member1})

위와 같이 views.py내의 premium_page_loader함수에서 PremiumMembers클래스의 인스턴스를 생성하고, 이 객체 자체를 render함수에 전달해주었습니다.

이제, 이를 받아올 템플릿에서 DTL을 사용해 member_A.user_age, member_A.user_name등에 접근할 수 있습니다.

아래는 수정된 템플릿 파일의 코드입니다.

<h1>{{member_A.user_name}}님의 {{member_A.user_age}}번째 생일을 축하합니다!</h1>

인스턴스의 수가 많아진다면.. 리스트로 전달하기

위의 예시에선 인스턴스를 하나만 생성했습니다.
그런데, 인스턴스의 수가 많아진다면 인스턴스를 하나 하나 전달하는 것도
그닥 효율적인 방법은 아닌 것 같습니다.

아래와 같이 리스트로 전달하여 가독성을 높이는 것이 좋겠습니다.

def premium_page_loader(request):
	member1 = PremiumMembers()
    member1.user_name = 'lee'
    member1.user_age = 30
    
    member2 = PremiumMembers()
    member2.user_name = 'kim'
    member2.user_age = 14
    
    member3 = PremiumMembers()
    member3.user_name = 'park'
    member3.user_age = 80
    
    members = [member1, member2, member3]

	return render(request, 'premium_page.html', {'members': members})

이제 템플릿 html파일에선, 객체를 요소로 가진 배열을 인덱싱하여
프리미엄 회원들의 정보에 접근할 수 있겠네요.

무엇보다, render함수의 가독성이 크게 향상되었습니다.

템플릿에서 동적으로 데이터 띄우기

이제 views.py에서 template으로 동적으로 데이터를 잘 전송하고 있으니,
이를 잘 받아와 적절하게 화면에 띄워주기만 하면 됩니다.

그런데, view에서 전달받은 인스턴스가 20개라고 가정해볼게요.
그럼, 각 요소에 대응하는 모든 html 태그들을 작성해야 하니,
파일의 크기가 너무 커질 뿐더러, 가독성도 저하됩니다.

다음과 같이 반복문을 사용해 템플릿 파일 내에서는 요소의 개수를 고정해두지 않고,
view에서 전달한 인스턴스의 개수만큼 html요소를 생성하도록 해봅시다.

{% for member in members %}
<div>
  <h2>{{member.user_name}}<h2/>
  <h2>{{member.user_age}}<h2/>
</div>
{% endfor %}

이렇게 하면, view에서 전달할 인스턴스의 개수가 변해도, template파일을 수정할 필요가 없어 코드의 유지보수가 쉬워집니다.

마치며(결론)..

model엔 데이터의 틀을 설계하고,
view엔 인스턴스를 생성한 뒤 이를 template으로 보내고,
template에선 DTL을 사용해 이를 받아와 동적으로 데이터를 사용합니다.

이상으로 글을 마칩니다.
도움이 되었다면 팔로우 부탁드립니다.

감사합니다.

profile
웹 풀스택 개발자를 준비하고 있습니다. MERN스택을 수상하리만큼 사랑합니다.

0개의 댓글