해리의 데브로그

Django 06 - CRUD 3 (Read)

|

Model을 활용한 CRUD 구현 (3)

Read (3) - 디테일 & 리스트 페이지 연결하기

#views.py
def index(request):
    posts = Post.objects.all()
    return render(request, 'index.html', {'posts':posts})
  • views.py - index 함수의 코드를 살펴보면, 모델 클래스인 Post 으로 작성된 레코드 전체를 갖고 오는 Post.objects.all() 메서드를 사용하여 posts 변수에 저장한 것을 알 수 있음.
  • posts 를 파이썬 쉘에서 불러오면, 다음과 같은 예시 결과가 뜸. 여기서 우리는 posts 라는 변수에는 Post 의 인스턴스들이 리스트에 저장 되어 있다는 것을 알 수 있음. 이를 활용하여, 반복문을 통해 posts 내 각각의 인스턴스 객체를 불러오는 작업을 index.html에서 할 수 있다.
>>> posts = Post.objects.all()
>>> posts
<QuerySet [<Post: 2번째로변경>, <Post: 추가번째>, <Post: 몇번째?>, <Post:  나는  수업시간만되면>, <Post: 민재야>, <Post: [개념글]>, <Post: [뻘글]>, <Post: [정보]>, <Post: [to harry]>, <Post: 66666>, <Post: [to harry]>, <Post: 1번째>, <Post: 배가왜이리>, <Post: 123123>]>
<-- index.html -->
<body>
    <a href="/posts/new/">New - 새로운 글쓰기</a>
    <ul>
    {% for post in posts %}
        <li><a href="/posts//"></a></li>    
    {% endfor %}
    </ul>
</body>
  • index.html 내 진자 템플릿을 이용하여 반복문을 사용하였으며, 리스트 내 인스턴스 객체를 불러오는 변수명을 post로 정의하였음. 반복문이 돌면서 리스트 내 객체가 하나씩 호출되는 과정은 아래와 같음.

    1번째 반복: post = <Post: 2번째로변경> => 기본주소/students/1 2번째 반복: post = => 기본주소/student/2 3번째 반복: post = <Post: 몇번째?> => 기본주소/student/3 ...

  • 각 객체는 post라는 Post 클래스의 인스턴스에 저장되어, post.pkpost.title 와 같이 클래스의 멤버변수를 호출하여 저장된 값을 불러올 수 있다.

  • 이를 활용하여, post.pk 를 a태그 내 링크 주소로 입력하면 variable routing 으로 반복문이 돌면서 각각의 인스턴스는 detail 함수(세부정보가 담긴 페이지를 호출하는 함수)를 불러오는 url patterns와 연결이 된다.

#urls.py
urlpatterns = [
    path('<int:post_id>/', views.detail),
]

Read (4) - new & create 페이지 연결

앞서 우리가 작성한 코드에서, new.html에 내용을 작성하면, create.html으로 연결되어 해당 웹페이지에 작성된 내용인 “성공적으로 Post되었습니다” 라는 화면을 사용자가 볼 수 있었음. 이부분을 수정하여, new.html에서 내용을 작성하면, 작성한 내용을 보는 페이지로 넘어가게 해보자.

이에 앞서, 클라이언트(웹 브라우저)에서 서버를 요청(request)을 보내는 방식을 Get에서 Post로 변경을 해보자.

  • Get: 가져오는것 (html 문서를 보여달라!)
  • Post: 수행하는 것

데이터베이스에 내용을 저장하는 행위는 단지, 데이터를 가져오는 역할을 하는 GET 방식보다는 POST 방식과 더 적합하다. 또한, POST 방식으로 데이터를 실어서 요청을 보낼 경우, 주소창에 데이터가 표시되지 않으므로 보안적인 측면에도 더 낫음.

<--! new.html -->
<form action="/posts/create/", method="post">
{% csrf_token %}

CSRF: 사이트 간 요청 위조(Cross-site Request Forgery)

웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격 방법

  • CSRF 토큰이란 CSRF 공격에 대응을 하기 위한 방어 기법 중 하나임. 보통 CSRF공격은 특정액션시 넘어가는 파라미터를 가지고 그 행위를 특정액션 이외에 자동으로 넘어가게 하는 기법인데 이것을 넘어가는 값 중에 랜덤으로 발행되는 키값을 넘기고 받게 해서 이 값이 일치하지 않으면 그 액션을 수행하지 않는 것이다.
  • CSRF token은 보안상의 목적으로 사용. token을 넣어줘야 token과 함께 create 페이지에 요청을 보냄. 장고에서 csrf token을 가지고, 피하식별 하듯이, 우리 사이트에서 보낸 요청이라는 것을 확실히 알 수 있게 됨.
  • Post 메소드를 쓸 때는 반드시 csrf_token이 있어야함.
from django.shortcuts import render, redirect

def create(request):
    title = request.POST.get('title')
    content = request.POST.get('content')
    
    post = Post(title=title, content=content)
    post.save()
    return redirect(f'/posts/{post.pk}')
  • views.py에서 메소드 방식을 GET => POST로 변경.
  • POST는 html 문서를 돌려주지 않음(반환 X). 그 대신 특정 페이지로 redirect 하게 지정 할 수 있음. redirect는 외장 함수 이므로 import 해줘야함.

최종 summary

1) new.html에서 사용자가 내용을 입력하면, form 태그에서 정의된 actionmethod 속성에 따라, 기본주소/posts/create/ url 주소를 서버에 요청함.
2) create 함수에서 정의된 내용에 따라, 입력된 내용이 각각 title & content 변수에 저장 3) 데이터베이스에 내용을 저장하기 위해 Model 클래스 인 Post 를 호출하여, 각각의 내용을 테이블의 구조에 맞게 저장한다 post = Post(title=title, content=content) (이때, post.save() 를 반드시 넣어야 데이터베이스에 내용이 저장됨을 잊지 말자) 4) 이후, redirect 함수에따라, /posts/{post.pk} 주소로 이동된다. (views.pydetail 함수 실행)

Comments