- 해당강좌: https://www.udemy.com/course/djangogirls-with-askdjango/learn/lecture/9431220#content
해당 튜토리얼: https://tutorial.djangogirls.org/ko/extend_your_application/
이제까지의 정리과정으로 웹사이트 제작단계를 모두 마쳤고, 이제 블로그 게시글이 각 페이지마다 보이게, url과 그에따른 뷰와 템플릿, 애플리케이션 통채로를 확장해보는 작업을 해보자.
블로그 게시글이 각 페이지마다 보이도록 제작한다는 것은, (주소)/1/
이면, 1번 포스트를, (주소)/2/
이면, 2번 포스트를 불러와서 보여지게 해보는 것이다.
애플리케이션의 urls.py 확장하기
# (애플리케이션명)/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
]
예전에 만들었던 urls.py 파일을 보면 위같이 만들어 주었다. 여기서 url 패턴으로, ''과 같이 아무 패턴이 없으면, 모두 views.post_list 라는 view함수로 연결해 주었다.
이때, 여기서 url 패턴을 추가해준다.
path('post/<int:pk>/', views.post_detail, name='post_detail'),
이와 같은 코드인데, post/(숫자)/
와 같은 url 패턴에 대해서, views.post_detail 이라는 view함수로 연결해주는 것이다.
여기서 url 패턴에 사용된, <int:pk>
는, int(정수)로 url의 값을 받아서, 그 값을 pk라는 변수에 담아서, view함수를 호출할 때 변수로 넘겨주는 뜻이다.
예를들어, (주소)/post/1/
이나 (주소)/post/100/
같이 url 값을 입력받을때는 이 패턴에 만족하지만, (주소)/post/1-/
같이 숫자가 아닌 값이 url에 추가된다면 패턴에 만족하지 않는 것이다.
애플리케이션의 views.py 확장하기
# (애플리케이션명)/views.py
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.all()
return render(request, 'blog/post_list.html', {'posts': posts})
그리고 예전에 작성한 views.py로 넘어가자.
새로만든 url 패턴에서 post_detail이라는 새로운 view함수를 연결해주었는데, 그 post_detail 이란 새 view함수를 정의해준다.
이 post_detail 함수는, 기본적으로 request 변수와 추가로 url 패턴에서 넘겨준 pk라는 변수값도 매개변수로 전달받는다.
이제 여기서 입력받은 url 패턴의 숫자에 대한 포스팅을 render로 불러올려면, 이 pk 변수로, 쿼리셋에 .get()의 조건으로 넣어주어서, pk 변수에 담긴 숫자의 순서와 일치하는 객체를 불러오면 된다. Post.objects.get(pk=pk)
이렇게 해서, 그러한 쿼리셋을 render() 함수에 리턴하게되면, 전체 코드는 아래와 같을 것이다.
# (애플리케이션명)/views.py
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.all()
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
posts = Post.objects.get(pk=pk)
return render(request, 'blog/post_detail.html', {'posts': posts})
참고로 여기서 이코드를 실행하면, 에러가 난다. blog/post_detail.html
이란 새로운 장고 템플릿을 불러주었기에 그렇다.
애플리케이션의 템플릿 확장하기
blog/post_detail.html
템플릿을 생성한 후에, (당연히 템플릿의 위치를 지켜서 생성해야 한다. 이에 대해선 1-10 참고)
{% extends 'blog/base.html' %}
{% block content %}
<h2>{{ post.title }}</h2>
{{ post.text }}
{% endblock %}
이제 이정도 까지 해주면, 에러없이 url의 주소 패턴의 숫자에 따라서, 그에 맞는 숫자의 객체를 불러오는 페이지를 보여줄 수 있다.
500 에러를 404 에러로 처리해주기
근데 이렇게 했을 경우의 문제가 하나있다.post/(숫자)/
같은 url 패턴에서, post/100000/
같이 100000 번째 객체를 view에서 불러오는 경우에, views.py의 함수에서,
DoesNotExist 오류가 나게 된다. 이렇게 되면 서버에선 500 에러를 내게 되는데, 이러면 좋은 서버 설계가 아니다.
이것은 파일이 없는 것이기에 404 오류를 내보내게 돼야될텐데,
try:
post = Post.objects.get(pk=pk)
except Post.DoesNotExist:
raise Http404
와 같이,
Post 객체에서, get(pk=pk)와 같이 객체를 검색했을 때, 찾은 객체가 없으면, except 문을 이용해서, Http404를 리턴해주면 된다.
근데 이렇게 4줄로 404를 검출할 수도 있지만, 단 한줄로도 해줄 수 있는데,
바로, django.shortcuts.get_object_or_404(Post, pk=pk)
와 같은 코드다.
get_object_or_404() 함수로 첫번째 인자는 모델 객체를, 두번째 인자는 객체를 검색하는 검출식을 검색한다.
이렇게 이 함수에서 그 검출식으로 모델에서 해당되는 객체를 찾게 되는데, 그 객체가 없으면 404를, 있으면 그 객체를 post 변수에 담아주는 것이다.
post_list, 루트 url에서 목록으로 연결해주기
{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<div class="date">
<p>{{ post.published_date }}</p>
</div>
<h1><a href="{{% url 'post_detail' post.pk %}}">{{ post.title }}</a></h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock %}
이제 루트파일에서 목록을 출력하는 페이지인, post_list.html
에서 위같이 코드를 작성해주어서 포스트별로 연결되는 리스트의 링크가 실제로 연결도 되게 작성하면 된다.
'웹(Web) > 장고(Django)' 카테고리의 다른 글
1-14. 장고 폼(form) (0) | 2021.01.14 |
---|---|
1-12. 장고 템플릿(templates) 확장하기(상속받기) (0) | 2021.01.14 |
1-11. 장고 정적(Static)파일, CSS로 웹페이지 예쁘게 만들기 (0) | 2021.01.14 |
1-10. 장고 템플릿의 심화 (0) | 2021.01.14 |
1-9. 템플릿 동적 데이터와 쿼리셋 (0) | 2021.01.14 |