본문 바로가기

문돌이 존버/Django 스터디

Mac 버전 장고 웹페이지 http request

반응형

오늘은 http request에 대해 전반적으로 살펴보려고 합니다. 먼저, 새로운 프로젝트를 생성해보겠습니다. 가상환경에 진입한 후, django-admin startproject mypost 를 입력합니다.  다음으로 새로운 앱을 생성하기 위해, mypost 디렉토리에서 python manage.py startapp myblog 를 입력합니다. 

이제 myblog에 있는 models.py 코드를 입력할 차례입니다. 아래를 참고하면 단순히 title과 content를 위한  Post class 를 생성한 것을 알 수 있습니다. 

from django.db import models

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=50)
    content = models.TextField()

    def __str__(self):
        return self.title

이후 mypost에 있는 settings.py INSTALLED_APPS 에 방금 만든 myblog 앱을 추가해줍니다. 이는 myblog에 있는 apps.py 파일의 MyblogConfig class를 가져오겠다는 의미입니다. 

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # My APP
    'myblog.apps.MyblogConfig'
]

아래는 views.py 파일의 코드입니다. 

from django.shortcuts import render, redirect

# Create your views here.
from .models import Post

def post(request):
    #print(request.method) 어떤 형태인지 확인해보기
    if request.method == 'POST':
        # DB값 추가 / POST 메소드는 딕셔너리 형태
        title = request.POST['title']
        content = request.POST['content']
        Post.objects.create(title=title, content=content)
        return redirect('post') 
    #print(request.POST): 사용자가 보낸 요청들을 딕셔너리 형태로 저장한 것을 확인
    
    #post_list.html에서 {%url 'post' %}가 가리키는 것은 veiws.py의 post 함수
    #글을 작성하지 않으면, 즉 request.method == 'GET'이라면 post_list 페이지로 render
    posts = Post.objects.all()
    return render(
        request,
        'mypost/post_list.html',
        {'posts': posts}
    )

mypost 폴더 안에 있는 urls.py 파일을 다음과 같이 수정합니다. include 모듈을 임포트하는 것 잊지마세요! 

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('mypost/', include('myblog.urls')) #myblog 내 url 주소를 포함하겠다는 의미
]

이어서 myblog 폴더 안에 있는 urls.py 파일 수정도 필요합니다. 

from django.urls import path

from . import views

urlpatterns = [
    path('', views.post, name='post')
]

다음은 views.py 에서 렌더링 변환 부분에서 미리 정의한 post_list.html 파일의 코드입니다. 

{% for post in posts %}
<br/>
<h2>{{ post.title }} </h2>
    <br/>
{{ post.content }}
<br/>

------------
{% endfor %}


<h3> 새로운 글 작성하기 </h3>

 <!--form, input, input submit-->
<form action="{% url 'post' %}" method="POST">
    {% csrf_token %} 
    <!--csrf_token을 명시해야 'input type 제출'을 눌렀을 때 오류가 나타나지 않음-->
    <!--사용자가 html 화면으로 렌더링할 때 장고가 사용자한테 보내주는 토큰값을 그대로 서버에 보내주는 것으로 사용자 인식이 가능-->
    <!--action="": form action에 해당하는 행동을 어디로 보낼 것인지--> 
    <!--method=POST: body 부분을 채워넣을 때 사용하는 메소드--> 
    제목 : <input name="title" /><br/>
    내용 : <textarea name="content" rows="20">
    </textarea>
    <input type="submit"/>
</form>

{% csrf_token %} 를 조금 더 설명하자면 장고 웹서버를 실행시키고 views.py 파일의 print(request.POST) 의 주석을 풀어주고 실행해보면 웹서버가 돌아가고 있는 환경에서 QueryDict 에 관한 내용이 나타날 것입니다. 이는 <QueryDict: {'csrfmiddlewaretoken': ['~~'], ~> 와 같은 형태로 구성되어 있습니다. 

위에 작성한 views.py 파일의 코드는 단계별로 작성된 것이 아닌 최종 코드를 보여주기 때문에 아래 부가적인 설명을 계속하겠습니다.

post_list.html 에서 설정한 <input type="submit" /> 에 따라 웹 페이지에 생긴 제출 버튼을 눌렀을 때 POST 메소드 요청이 views.pypost 함수로 들어오게 됩니다. request 메소드가 POST이기 때문에 if문 안의 코드가 실행이 됩니다. 이후 redirect 하면 'post'라는 이름을 가진 경로로 사용자가 보낸 request가 보내지게 되는데, 이 경우에 urls.py 안의 'post'라는 이름을 가진 경로, 즉 다시 views.py의 함수 post로 되돌아오는 것이죠. 다음부터는 if문을 돌지 않고 바로 post = Posts.objects.all() 부터 명령을 실행하는 것입니다. 터미널을 살펴보면 POST -> GET 요청이 연속으로 이루어짐을 알 수 있습니다. 

return redirect('post') 가 없다면 웹 페이지 화면에서 새로고침을 할 때마다 똑같은 글이 계속 작성되는 것을 발견할 수 있습니다. 사용자가 처음에 보낸 request가 그대로 사용자에게 되돌아오기 때문입니다. 즉 사용자가 POST 메소드를 통해 보낸 request가 form data에 그대로 남아있는 상황이고 redirect하지 않기 때문에 웹에서는 GET 메소드를 통해 기존에 받았던 request를 데이터베이스에 계속 추가하는 것입니다. 

따라서 return redirect() 를 해줘서 사용자가 POST 메소드로 보낸 request 를 없앤 뒤 새로운 요청에 해당하는 내용을 GET 메소드를 이용해 받습니다. 이후 다시 사용자에게 보내주면 저희가 제출한 새로운 title과 comment가 반영되는 것입니다. 아래는 위의 코딩 결과를 보여주는 최종 웹 페이지고, 제목과 내용 부분에 자유롭게 작성하면 실시간으로 반영된답니다. 

728x90
반응형