개요
지금까지 데이터를 저장할 데이터베이스와의 연동과 데이터를 생성하고 읽고 갱신하고 삭제(CRUD - Create Read Update Delete)하는 방법, 그리고 사용자가 접속할 URL을 생성하는 방법 등 장고(django)로 웹 서비스를 하기 위한 많은 작업을 진행하였습니다. 이번 블로그에서는 사용자에게 보여줄 웹 페이지를 만들기 위해 장고(django)의 뷰(View)를 사용하는 방법에 대해서 알아보겠습니다.
이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.
- 장고(django) 설치하기
- 장고(django) 프로젝트 시작하기
- 장고(django) 모델(models) 사용해보기
- 장고(django)의 관리자 페이지
- 장고(django)의 라우팅(Routing)
- 장고(django)의 ORM
- 장고(django)의 뷰(View)
- 장고(django)의 폼(Form)
- 장고(django) 프로젝트를 헤로쿠(heroku)에 업로드하기
또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.
URL 확인
이전 블로그(장고(django)의 라우팅(Routing))에서 우리는 사용자가 접속할 URL과 정적 HTML을 연결하는 방법에 대해서 알아보았습니다. 아래에 장고(django) 명령어를 실행하여 테스트 서버를 시작한 후, http://127.0.0.1:8000/
에 접속하면 Hello World
가 표시되는 웹 페이지를 확인할 수 있습니다.
# source venv/bin/activate
# cd django_exercise/
python manage.py runserver
데이터 전달
이제 이전 블로그(장고(django)의 ORM)에서 생성한 데이터를 웹 페이지에서 보기 위해 뷰(View)에 데이터를 전달해 보도록 하겠습니다. blog/views.py
를 열고 아래와 같이 수정합니다.
from django.shortcuts import render
from .models import Post
def posts(request):
posts = Post.objects.filter(published_at__isnull=False).order_by('-published_at')
return render(request, 'blog/posts.html', {'posts': posts})
from .models import Post
: 우리가 만든Post
모델(Models)을 불러옵니다.posts = Post.objects.filter(published_at__isnull=False).order_by('-published_at')
published_at__isnull=False
: published_at 필드가 null이 아닌 경우(__isnull=False
)에 데이터를 가져옵니다order_by('-published_at')
: 데이터를published_at
필드로 내림차순 정렬합니다.
return render(request, 'blog/posts.html', {'posts': posts})
: 가져온 데이터를blog/posts.html
페이지에{'posts': posts}
posts란 변수명으로 전달합니다.
데이터 표시
이제 위에서 전달한 데이터를 화면에 표시해 봅시다. blog/templates/blog/posts.html
파일을 열고 아래와 같이 수정합니다.
<html>
<head><title>Hello World</title></head>
<body>
{% for post in posts %}
<div>
<h1>
{{ post.title }}<small>(published: {{ post.published_at }})</small>
</h1>
<p>{{ post.content | linebreaksbr }}</p>
</div>
{% endfor %}
</body>
</html>
{% for post in posts %}...{% endfor %}
: 위에서blog/views.py
에서 전달한posts
데이터 리스트에서post
로 데이터를 하나씩 가져와 반복문을 돌립니다.{{ post.title }}<small>(published: {{ post.published_at }})</small>
: post 데이터의title
/published_at
필드값을 표시합니다.<p>{{ post.content | linebreaksbr }}</p>
: 우리가 가지고 있는 post 데이터의content
를 가져와 줄바꿈(\n
)을 줄바꿈 태그(<br/>
)로 변환하여 표시합니다.
위와 같이 코드를 수정하고 http://127.0.0.1:8000/
에 접속하면 아래와 같이 데이터가 표시되는 것을 확인할 수 있습니다.
조금 더 연습을 하기 위해 상세 페이지를 제작해 봅시다. 위에서 만든 blog/templates/blog/posts.html
파일을 아래와 같이 수정합니다.
<html>
<head><title>Hello World</title></head>
<body>
{% for post in posts %}
<a href="{% url 'post_detail' id=post.id %}"> <!-- <<<<<<<<<<<<<<<<<<<<< here -->
<h1>
{{ post.title }}<small>(published: {{ post.published_at }})</small>
</h1>
<p>{{ post.content | linebreaksbr }}</p>
</a> <!-- <<<<<<<<<<<<<<<<<<<<< here -->
{% endfor %}
</body>
</html>
{% url 'post_detail' id=post.id %}
: 우리가 정의한django_exercise/urls.py
와blog/urls.py
에서post_detail
이라는 이름(name)을 찾고 해당 URL로 변경해 줍니다. 이때id
라는 파라메터를 만들고Post
의 id를 넣어줍니다.
아직은 post_detail
과 매칭되는 URL을 만들지 않았습니다. 이제 post_detail
과 대응하는 URL과 뷰(View)를 제작해 봅시다. blog/templates/blog/post_detail.html
을 생성하고 아래와 같이 수정합니다.
<html>
<head><title>Hello World</title></head>
<body>
<a href="{% url 'posts' %}">
Post List
</a>
<h1>
{{ post.title }}
</h1>
<p>created: {{ post.created_at }}</p>
<p>updated: {{ post.updated_at }}</p>
<p>published: {{ post.published_at }}</p>
<p>author: {{ post.author.username }}</p>
<p>{{ post.content | linebreaksbr }}</p>
</body>
</html>
{% url 'posts' %}
: URL 파일에서posts
라는 이름(name)을 갖는 URL을 찾고 그 URL로 대체합니다.author: {{ post.author.username }}
: 우리는 우리가 만든Post
모델과 장고(django)에서 기본적으로 제공하는auth.User
과 연결하여 작성자(author
) 필드를 만들었습니다. 이렇게 연결한 모델(Models)에서username
을 가져와 표시하였습니다.
이제 화면에 표시할 페이지는 준비되었습니다. blog/urls.py
를 열고 아래와 같이 수정합니다.
from django.urls import path
from . import views
urlpatterns = [
path('', views.posts, name='posts'),
path('post/<int:id>/', views.post_detail, name='post_detail'), # <<<<<<<<<<<< here
]
post/<int:id>/
: URL에 파라메터로 넘어온 숫자형 데이터id
를 표시합니다.name='post_detail'
: URL의 이름은post_detail
이며views.post_detail
와 매핑되어있습니다.
이로써 {% url 'post_detail' id=post.id %}
을 사용하여 post/<int:id>/
URL을 표시하고 views.post_detail
과 매핑 시킬 준비가 되었습니다. 이제 blog/views.py
파일을 열고 아래와 같이 수정합니다.
from django.shortcuts import render, get_object_or_404 # <<<<<<<<<<<< here
from .models import Post
def posts(request):
posts = Post.objects.filter(
published_at__isnull=False).order_by('-published_at')
return render(request, 'blog/posts.html', {'posts': posts})
# <<<<<<<<<<<< here
def post_detail(request, id):
post = get_object_or_404(Post, id=id)
return render(request, 'blog/post_detail.html', {'post': post})
get_object_or_404
: 장고에서 기본적으로 제공하는 함수를 추가하였습니다. 이 함수는 해당 객체(Object)에서 데이터를 가져오는데 데이터가 없으면404
에러를 발생시키는 함수입니다.def post_detail(request, id):
: 새롭게 추가한 URL과 매핑되는 함수입니다. 파라메터로 넘겨준id
를 별도의 변수로 전달받을 수 있습니다.
이것으로 상세 페이지를 제작해 보았습니다. http://127.0.0.1:8000
으로 접속하면 이전과는 다르게 아래와 같이 링크가 걸린 페이지를 볼 수 있습니다.
해당 링크를 누르면 상세페이지 URL(http://127.0.0.1:8000/post/2/
)로 이동하며 아래와 같이 Post
의 상세 페이지를 확인할 수 있습니다.
템플릿 파일
이제 뷰(View)와 URL, 그리고 데이터를 표시하는 방법은 어느정도 익숙해진거 같습니다. 하지만 HTML 파일에 중복되는 코드가 많습니다. 아직 css, js
나 meta
태그를 넣지 않았지만, 이런 태그들이 많아지면 점점 중복되는 코드들이 많아지기 시작합니다. 이런 중복되는 부분을 새로운 파일로 만들고 가져오는 방법에 대해서 알아보도록 하겠습니다.
일단 정적 파일(css, js 등
)을 추가하는 방법에 대해서 알아보겠습니다. blog/static/css/main.css
파일을 생성하고 아래와 같이 수정합니다.
h1 {
color: red;
}
여기에서는 디자인에 관해서는 다루지 않겠습니다. 더 이쁘게 꾸미고 싶으신 분들은 이 파일을 수정하시기 바랍니다. 장고(django)는 static
이라는 이름의 폴더를 자동으로 찾아 등록하기 때문에 추가적인 등록 과정은 필요하지 않습니다.
이제 blog/templates/blog/layout.html
파일을 생성하고 아래와 같이 수정합니다.
{% load static %}
<html>
<head>
<title>Hello World</title>
<link rel="stylesheet" href="{% static 'css/main.css' %}" />
</head>
<body>
{% block content %} {% endblock %}
</body>
</html>
{% load static %}
: 이 파일에서static
폴더를 사용할 수 있도록static
폴더를 불러옵니다.<link rel="stylesheet" href="{% static 'css/main.css' %}" />
: 우리가 불러온static
폴더에서css/main.css
를 찾아 URL로 변경합니다.{% block content %} {% endblock %}
: 이 레이아웃(layout) 파일에 필요한 데이터(content
)를 표시할 위치를 설정합니다. 이렇게 표시하고 싶은 부분을block [name]
으로 설정하고 해당 블록(block)을 대체할 부분을[name]
을 사용하여 대체합니다.
이제 레이아웃(layout) 파일을 활용하기 위해 blog/templates/blog/posts.html
파일을 열고 아래와 같이 수정합니다.
{% extends 'blog/layout.html' %}
{% block content %}
{% for post in posts %}
<a href="{% url 'post_detail' id=post.id %}">
<h1>
{{ post.title }}<small>(published: {{ post.published_at }})</small>
</h1>
<p>{{ post.content | linebreaksbr }}</p>
</a>
{% endfor %}
{% endblock %}
{% extends 'blog/layout.html' %}
: 이 파일(posts.html)은 우리가 만든 레이아웃(layout.html) 파일을 활용합니다.{% block content %}...{% endblock %}
: 우리가 레이아웃(layout.html) 파일에 만든 블록(block), 그중에 이름이content
인 블록(block)을 여기에 작성한 내용으로 대체합니다.
그리고 blog/templates/blog/post_detail.html
파일을 열고 아래와 같이 수정합니다.
{% extends 'blog/layout.html' %}
{% block content %}
<a href="{% url 'posts' %}">
Post List
</a>
<h1>
{{ post.title }}
</h1>
<p>created: {{ post.created_at }}</p>
<p>updated: {{ post.updated_at }}</p>
<p>published: {{ post.published_at }}</p>
<p>author: {{ post.author.username }}</p>
<p>{{ post.content | linebreaksbr }}</p>
{% endblock %}
위에서 설명한 내용과 동일하게 레이아웃(layout.html) 파일을 활용하고 이름이 content
인 블록(block)을 여기에 작성한 내용으로 대체합니다.
확인
실제 작업한 내용을 확인하기 위해 http://127.0.0.1:8000/
에 접속해 봅니다. 그러면 우리가 작성한 css
가 적용된 화면을 아래와 같이 볼 수 있습니다.(화면이 제대로 표시되지 않는 다면 테스트 서버를 재실행 해 보세요.)
링크를 눌러 상세 페이지(http://127.0.0.1:8000/post/2/
)에 이동해도 아래와 같이 css
가 적용된 것을 확인할 수 있습니다.
이것으로 우리는 장고(django)의 템플릿을 활용하여 정적 파일(css, js 등)을 가져오는 방법과 HTML의 중복 줄이기 위한 방법에 대해서 알아보았습니다.
완료
이번 블로그에서는 장고(django)의 뷰(View)를 활용하는 전박적인 방법에 대해서 살펴보았습니다. 데이터를 가져와 화면에 출력하고, 출력하는 화면을 잘 관리하기 위한 장고(django)의 템플릿도 확인해 보았습니다. 또한 css와 js같은 정적 파일(static)을 가져오는 방법에 대해서도 알아 보았습니다. 이제 우리는 이것들을 활용하여 일반적인 웹 서비스 사이트를 제작할 수 있게 되었습니다!
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku
가 개발한 앱을 한번 사용해보세요.Deku
가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.