완숙의 블로그

[Django] Week 4_1 pk, path converter, get_object_or_404 본문

Programing Language/Web_Django

[Django] Week 4_1 pk, path converter, get_object_or_404

완숙 2019. 2. 26. 21:00

블로그 게시판을 바꿔보자!

  1. home에서 글자수가 100개만 보이게
  2. ...more 라는 링크달기
  3. 링크를 클릭하면 detail.html이 나오도록

 

1. home에서 글자수가 100개만 보이게

# model.py
from django.db import models

# Create your models here.


class Blog(models.Model):
    title = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    body = models.TextField()

    def __str__(self):
        return self.title

여기서 아래에 추가해준다.

	def summary(self):
        return self.body[:100]

 

이제 home.html 로 가서, 우리가 원하는 녀석으로 내용부분을 바꿔줘야 한다.

# home.html before
{% for blog in blogs.all%}
    <h1> 제목 : {{blog.title}} </h1>
    <p> 날짜 : {{blog.pub_date}} </p>
    <p> 본문 미리보기 : {{blog.body}} </p> # 요 부분!
    <br><br>
{%endfor%}
# home.html after
{% for blog in blogs.all%}
    <h1> 제목 : {{blog.title}} </h1>
    <p> 날짜 : {{blog.pub_date}} </p>
    <p> 본문 미리보기 : {{blog.summary}} </p> # 이렇게!
    <br><br>
{%endfor%}

 

2. ...more 라는 링크달기

# home.html
{% for blog in blogs.all%}
    <h1> 제목 : {{blog.title}} </h1>
    <p> 날짜 : {{blog.pub_date}} </p>
    <p> 본문 미리보기 : {{blog.summary}} <a href = "">more...</a> </p> 
										<!-- a 태그로 달아준다. 일단은 url은 안했다. -->
    <br><br>
{%endfor%}

 

3. 링크를 클릭하면 detail.html이 나오도록

자, 그런데 글이 몇개 없을 때는 위의 href 태그의 링크를 일일히 달아주면 되겠지만 글이 많아진다면 굉~장히 수고스러운 일이 된다(ㅠ)

그렇기 때문에 우리는 detail.html의 형식은 하나만 만들고, 그 안의 내용은, 내가 어떤 글을 눌렀느냐에 따라 달라지게 만드는 것이 합리적이다!

2019-02-13 11 19 33

또한 n번째 글이 없다면, 404 에러를 띄우도록 하자!

 

할일 정리

  1. x 번째 블로그 객체를 request 하면, x번 객체의 내용을 띄운다. => pk
  2. url 설계 = 우리 사이트/blog/객체번호(x) => path converter
  3. 있지도 않은 글(객체)를 요청하면 404에러를 띄우자! => get_object_or_404

 

시작

  1. 사용자 입장에서 링크를 누른다(request , action)
  2. url 을 알려준다.
  3. Django 안 MTV 패턴에 의해 돌아간다.

 

따라서 우리는 url 부터 만져줘야 한다.

2019-02-13 11 34 05

 

URL 설계

링크를 눌렀을 때 보여질 detail이라는 함수를 views.py에 만들었다고 가정해보자.

# views.py
from django.shortcuts import render
from .models import Blog # 동일한 폴더를 말할 때 . 을 사용, 거기서 Blog라는 클래스를 불러와라

def home(request):
    blogs = Blog.objects # Blog 라는 클래스안에 있는 객체를 blogs라는 녀석에 담을 거다.
    return render(request, 'home.html', {'blogs' : blogs}) # 마지막 인자는 딕셔너리 형으로

def detail(request, blog_id):
# Create your views here.

인자로 들어가는 blog_id 는 조금만 있다가 생각해보자.

 

그럼 url.py 를 보자.

# url.py before
from django.contrib import admin
from django.urls import path
import blog.views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', blog.views.home, name = "home"),
]

 

여기서 어떤 경로를 누르면 무엇을 보여줘야 할텐데, 지금 위의 그림을 보면, 내주소/blog/2 와 같은 형식으로 path가 결정될 것이므로, blog/<int:blog_id> 로 잡아준다.

이 때, <int:blog_id> 를 path converter 라 한다!

  • int내주소/blog/정수 와 같은 형태로 설계하겠다는 의미이다.
  • blog_id 이 녀석은 views.py 에 있는 detail 함수에 넘겨줄 인자 이다!

 

결국, 이렇게 표현해야 한다.

# url.py after
from django.contrib import admin
from django.urls import path
import blog.views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', blog.views.home, name = "home"),
    path('blog/<int:blog_id>', blog.views.detail, name="detail"),
]

 

 

잉? 왜 인자가 필요하지?

# views.py 
from django.shortcuts import render
from .models import Blog # 동일한 폴더를 말할 때 . 을 사용, 거기서 Blog라는 클래스를 불러와라

def home(request):
    blogs = Blog.objects # Blog 라는 클래스안에 있는 객체를 blogs라는 녀석에 담을 거다.
    return render(request, 'home.html', {'blogs' : blogs}) # 마지막 인자는 딕셔너리 형으로

def detail(request, blog_id):
# Create your views here.

views.py 에서 home 함수같은 경우는, 우리가 url을 땅! 하고 치는 action(request)만 있으면 우리가 만들어놓은 화면을 보여주기만 하면된다.

그런데 지금 만드는 detail이라는 함수는, 어떤 링크를 누르냐에 따라 그것에 맞는 정보를 보여주어야 한다.

그것을 구분할 수 있게 만드는 것이 url.py 에서 봤던 blog_id 이다. detail 함수는 이 값을 인자로 받아 이 숫자에 해당하는 화면을 보여주어야 한다. 따라서 request, blog_id 두개를 인자로 받는다!

 

즉, 사용자가 어떤 걸 선택하느냐와 직접적으로 연관이 있는 url에서 이 정보를 미리 만져주고,

이 정보를 views로 인자로 던져버려, 사용자가 원하는 객체를 가져올 수 있게 한다!

 

path converter

<type : 변수이름>
    
    type의 예 : int, str, uuid...

 

  • 계층적인 url을 자동생성할 때 유리!

 

 

Detail 함수 만들기

# views.py 

def detail(request, blog_id):
    blog_detail = 이용자가 원하는 몇번째(blog_id) 블로그 객체
    
    return render(request, 'detail.html', {blog':blog_detail'})

 

어떻게 blog_id번째 블로그 객체 를 가져올 수 있을까?

 

# views.py 

def detail(request, blog_id):
    blog_detail = get_object_or_404(Blog, pk = blog_id)
    
    return render(request, 'detail.html', {blog':blog_detail'})

 

여기서 get_object_or_404 함수가 등장한다!

이 함수는 어떤 클래스로 부터 몇번째 객체를 받아올 것인가에 대한 함수.

 

get_object_or_404(어떤 클래스, 검색조건) 이렇게 2개의 인자를 받는다.

  1. 어떤 클래스로 부터 정보를 가져올지에 대한 정보. 여기서는 Blog라는 클래스에서 정보를 가져온다. (models.py에 있는)
  2. 검색조건(몇번 데이터? = pk)

 

pk??

  • primary key의 약자

같은 클래스로 부터 객체들이 태어날텐데, 우리는 그것들을 구분할 방법이 없다.

그래서 그 녀석들을 구분할 수 있게 해주는 인식표 를 달아주는 값!

 

지금 같은 경우는 글 양식을 한개의 단위로 보았을 때, 새글이 태어나는 것은 그 전 글양식과 비슷할 것!

이 각각의 녀석들을 구분해주는 것이 pk라고 생각하면 쉽다!

이 구분하는 숫자를 url에서 우리는 무엇을 받았냐면, blog_id로 받았었다!

그래서 blog_id를 pk 값으로 선정한 것!

 

그런데, 이 get_object_or_404 를 사용하기 위해서는 import를 해줘야 한다.

그래야 사용할 수 있기 때문!

# views.py 
from django.shortcuts import render, get_object_or_404 # 이렇게 인포트 해준다!
from .models import Blog 

def home(request):
    blogs = Blog.objects 
    return render(request, 'home.html', {'blogs' : blogs}) 

def detail(request, blog_id):
    blog_detail = get_object_or_404(Blog, pk = blog_id) # 인자는 (클래스, pk)
    
    return render(request, 'detail.html', {blog':blog_detail'})

 

views.py 까지 작성했으므로 이 녀석을 보여줄 detail.htmltemplates 폴더안에 만들어주자.

 

이번에는 detail.html 에 어떤 녀석을 작성해야될 지 생각해보자.

<!-- detail.html-->
<h1> 자세한 본문 내용입니다. </h1>
<br><br>
<h1> 제목 : {{blog.title}} </h1>
<p> 작성 날짜 : {{blog.pub_date}} </p>
<p> 자세한 본문 : {{blog.body}} </p>

이런식의 내용이 들어가야 할 것이다!

 

자, 그러면 home.html 에서 ...more 을 누르면, detail.html 이 뜨도록 만들어주면 된다!

그러면 다시 home.html 로 들어가서, <a> 태그로 감싸진 href 에 이 경로를 추가해주면 된다.

home.html 은 html 파일이므로 파이썬 파일로 작성된 url.py 에 있는 url을 불러오려면 템플릿 변수를 사용해야 한다.

이 때, 해당 경로는 detail 이라고 이름을 설정해 줬으므로, 다음과 같이 적어주면 된다!

 

<!-- home.html -->
{% for blog in blogs.all%}
    <h1> 제목 : {{blog.title}} </h1>
    <p> 날짜 : {{blog.pub_date}} </p>
    <p> 본문 미리보기 : {{blog.summary}}  <a href = "{% url 'detail' %}">more...</a> </p>
	<!-- 이렇게! -->
    <br><br>
{%endfor%}

 

자, 근데 여기까지 쓰면 조금 아쉽다!

url.py 를 보면 어떤 경로를 받았을 때 views.py 에 있는 detail 함수를 부르냐면,

'blog/<int:blog_id>' 이 경로를 받았을 때, 넘어갈 수 있다.

그런데 home.html 을 보면, 넘어가는 url에서 몇번째 객체를 눌렀는지 알 수 없다.

어떻게 이 문제를 해결할까?

 

html에서 사용할 수 있는 파이썬 변수를 관장하는 views.py 에서 home 함수를 보자.

# views.py
def home(request):
    blogs = Blog.objects 
    return render(request, 'home.html', {'blogs' : blogs}) 

 

home 함수가 이렇게 정의되어 있기 때문에 우리는 home.html 에서 blogs 라는 객체를 템플릿 변수를 사용해서 사용할 수 있다.

home.html 에서 for 문을 돌면서 객체하나씩을 출력하기 때문에, 하나의 for 문을 돌 때, 그 객체의 index(번호)를 알아낼 수 있다면! 그것이 곧 url.py 에 넘어갈 blog_id 로 생각할 수 있을 것이다.

위의 for문에서 blogs.all 를 도는 변수를 blog 로 잡았기 때문에 우리는 이 blog 의 번호가 필요하다!

이 번호는, blog.id 로 접근가능하다!

 

따라서 우리는 home.html 을 다음과 같이 써줘야 한다.

<!-- home.html -->
{% for blog in blogs.all%}
    <h1> 제목 : {{blog.title}} </h1>
    <p> 날짜 : {{blog.pub_date}} </p>
    <p> 본문 미리보기 : {{blog.summary}}  <a href = "{% url 'detail' blog.id %}">more...</a> </p>
	<!-- 이렇게! -->
    <br><br>
{%endfor%}

 

 

이제 서버를 켜보면,

 

2019-02-14 5 01 19

 

짠!

 

Comments