📎 생성기능 구현

👉 목표

이번에는 글을 작성하는 부분을 만들어본다.

title을 작성하는 부분과 글의 body를 작정하고 제출 버튼을 누르면 topics에 추가가 된다. 그리고 새로 생성된 topic을 클릭하면 그 페이지의 상세보기 페이지로 이동하는 기능을 만드는 것이 목표다.


📎 GET method & POST method

myapp > views.py

# line 23 ~ 27 부분을 이렇게 수정
		</ul>
		{articleTag}
		<ul>
			<li><a href="/create/">create</a></li>
		</ul>
# line 47 ~ 56 create함수 수정
def create(request):
		article = '''
        <form action"/create/">
        	<p><input type="text" name="title" placeholder="title"></p>
            <p><textarea name="body" placeholder="body"></textarea></p>
            <p><input type="submit"></p>
        </form>
        '''
        return HttpResponse(HTMLTemplate(article))
            

다음과 같이 수정하고, 페이지로 가서 페이지 속성으로 들어간 뒤 , form의 title과 body에 글을 작성하고 제출을 누르면 어떤 형식으로 전송을 했는지 request method를 확인할 수 있다.
request method를 확인하는 것은 왜 중요할까? 서버에서는 주어진 리소스에 수행하길 원하는 행동을 메소드를 통해 구분하여 수행하기 때문이다. 따라서 메소드에 따라서 수행하는 작업이 다르다. request method에는 GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, HATCH, TRACE가 있지만 GET과 POST가 대부분이다.

👉 GET method

Get메소드는 주로 데이터를 읽거나(read) 검색(retrieve)할 때 사용되는 메소드이다.(=리소스를 검색하고 반환 받기 위한 메소드) 만약에 GET요청이 성공적으로 이루어진다면 XML이나 JSON과 함께 200 (Ok) HTTP 응답 코드를 리턴한다. 에러가 발생하면 주로 404 (Not found) 에러나 400 (Bad request) 에러가 발생한다.

HTTP 명세에 의하면 GET 요청은 오로지 데이터를 읽을 때만 사용되고 수정할 때는 사용하지 않는다. 따라서 이런 이유로 사용하면 안전하다고 간주된다. 즉, 데이터의 변형의 위험없이 사용할 수 있다는 뜻이다. 게다가 GET 요청은 idempotent하다. 즉, 같은 요청을 여러 번 하더라도 변함없이 항상 같은 응답을 받을 수 있다. 그러므로 GET을 데이터를 변경하는 등의 안전하지 않은 연산에 사용하면 안된다.

👉 POST method

POST 메소드는 주로 새로운 리소스를 생성(create)할 때 사용된다. 조금 더 구체적으로 POST는 하위 리소스(부모 리소스의 하위 리소스)들을 생성하는데 사용된다. 성공적으로 creation을 완료하면 201 (Created) HTTP 응답을 반환한다. POST 요청은 안전하지도 않고 idempotent하지도 않다. 다시 말해서 같은 POST 요청을 반복해서 했을 때 항상 같은 결과물이 나오는 것을 보장하지 않는다는 것이다. 그러므로 두 개의 같은 POST 요청을 보내면 같은 정보를 담은 두 개의 다른 resource를 반환할 가능성이 높다


📎 localhost:8000/read/1 VS localhost:8000/read/?id=1

👉 localhost:8000/read/1

이 url의 기능(의미)는 id가 1인 글을 읽어오는 것이다.

👉 localhost:8000/read/?id=1

앞서 다루었던 url(http://localhost:8000/read/1)의 표준적이고 전통적인 표현 방식이다. url뒤의 ?id=1은 이렇게 작성할 시, id가 1이라고 하는 값이 read로 전달된다. 추가로 model에 대한 값을 주고 싶다면 &mode=… 이런식으로 입력해서 전달하고자 하는 값을 추가할 수 있다. 이러한 문자열을 query string이라고 한다. query string은 서버에게 어떤 정보를 질의할 때 쓰는 문자열이다.

🖇️ query string

query string은 사용자가 정보를 전달하는 방법 중에 하나로 url주소에 미리 협의된 데이터(우리가 적어놨으니 협의 되었다고 표현)를 파라미터를 통해 전달하는 것을 말한다.
* 참고: query: noun: 문의, 의문 verb: 묻다, 질문하다, 의문을 제기하다

👉 localhost:8000/create/?title=CRUD&body=CRUD+is+...

제목의 url은 브라우저가 서버에 있는 데이터를 변경하려고 하는 작업이다.
만약 저렇게 적힌 url을 많은 사람들에게 공유한다면 큰일이 벌어지게된다. 왜냐하면 사람들이 클릭할 때 마다 새로운 페이지가 추가되기 때문이다. 따라서 브라우저가 서버의 데이터를 변경할 때는 query string을 넣는 것은 절대로 안되며 POST방식을 사용하게 된다.


📎 request, response, object

👉 create 함수의 작동원리

create func in view.py

def create(request):
		article = '''
				<form action="/create/" method="post">
						<p><input type="text" name="title" placeholder="title"></p>
						<p><textarea name="body" placeholder="body"></textarea></p>
						<p><input type="submit"></p>
				</form>
		'''
		return HttpResponse(HTMLTemplate(article)) # HTMLTemplate is just function defined as  the html template by me. 
																							 # I didn't import HttpResponse because there are two more the functions

사용자의 요청(어떤 방식으로 접속했는지 알 필요가 있다.)이 들어옴 → jango가 요청을 받음 → jango가 요청을 분석 후, create함수 호출 → 첫 번째 parameter의 인자로 http request라는 객체를 만들고(객체 안에는 사용자가 요청한 여러 정보를 패키징한 객체 형태로 담고 있음) 사용자에게 공급 → form tag로 묶여있는 코드(이 객체를 처리하는 코드)에서 객체가 처리됨. → http response라는 객체에 응답해주면, 그 정보가 jango에 의해서 사용자의 browser로 전송되게 된다.

🖇️ HTTP request vs response

request

클라이언트가 서버에게 연락하는 것을 request라고 하며, 요청을 보낼때는 요청에 대한 정보를 담아 서버로 보낸다.
HTTP request message는 start line, headers, body로 구성된다.

  • start line
    HTTP method, request target, HTTP version으로 구성된다. HTTP method는 위에서도 살펴봤듯이 요청의 의도를 담고 있는 GET과 POST 등을 말한다. request target은 HTTP request가 전송되는 목표 주소이다. HTTP version은 version에 따라 request 메시지 구조나 데이터가 다를 수 있기 때문에 명시한다.
  • headers
    general headers, request headers, entity headers로 구성된다. headers에는 다양한 header값들이 존재한다.
  • body
    HTTP request가 전송하는 데이터를 담고 있는 부분이다. 만약, 전송하는 데이터가 없다면 body부분은 비어있다. 보통 post 요청일 경우, HTML 폼 데이터가 포함되어 있다.

response

서버가 요청에 대한 답변을 클라이언트에게 보내는 것을 response라고 한다. status line, headers, body로 구성된다.

  • status line
    HTTP response의 상태를 간략하게 나타내주는 부분으로 HTTP version, status code, status text로 구성된다.
  • headers
    request의 headers와 동일하다. 그러나 response에서만 사용되는 header 값들이 있다.
  • body
    request의 body와 일반적으로 동일하다. 모든 response가 body가 있지는 않으며, 데이터를 전송할 필요가 없을 경우, body가 비어있게 된다.

👉 create 함수 수정

.method

django request and response objects공식 문서에서 HttpRequest.method를 이용하면 사용자가 어떤 방식으로 접속했는지 알 수 있다. 이를 이용해 create함수를 수정할 것이다.

if request.method == "GET"
		do_something()
elif request.method == "POST"

create 함수 수정 part1

@csrf_exempt # csrf 보안 방식을 끄는 명령어
def create(request):
		if request.method == "GET":
				article = '''
						<form action="/create/" method="post">
								<p><input type="text" name="title" placeholder="title"></p>
								<p><textarea name="body" placeholder="body"></textarea></p>
								<p><input type="submit"></p>
						</form>
				'''
				return HttpResponse(HTMLTemplate(article))
		elif request.method == "POST":
				print(request.POST)
				return HttpResponse('')

create 함수 수정 part2

@csrf_exempt 
def create(request):
		if request.method == "GET":
				article = '''
						<form action="/create/" method="post">
								<p><input type="text" name="title" placeholder="title"></p>
								<p><textarea name="body" placeholder="body"></textarea></p>
								<p><input type="submit"></p>
						</form>
				'''
				return HttpResponse(HTMLTemplate(article))
		elif request.method == "POST":
				return HttpResponse(request.POST['title']) # HttpRequest.POST 메소드를 사용(Django 공식 문서 참조)

'''
About HttpRequest.POST
A dictionary-like object containing all given HTTP POST parameters, 
providing that the request contains form data. See the QueryDict documentation below. 
If you need to access raw or non-form data posted in the request, 
access this through the HttpRequest.body attribute instead.

It’s possible that a request can come in via POST with an empty POST dictionary 
– if, say, a form is requested via the POST HTTP method but does not include form data. 
Therefore, you shouldn’t use if request.POST to check for use of the POST method; 
instead, use if request.method == "POST" (see HttpRequest.method).

POST does not include file-upload information. See FILES. 
'''

create 함수 수정 part3

@csrf_exempt 
def create(request):
		if request.method == "GET":
				article = '''
						<form action="/create/" method="post">
								<p><input type="text" name="title" placeholder="title"></p>
								<p><textarea name="body" placeholder="body"></textarea></p>
								<p><input type="submit"></p>
						</form>
				'''
				return HttpResponse(HTMLTemplate(article))
		elif request.method == "POST":
				title = request.POST['title']
				body = request.POST['body']
				newTopic = {"title":title, "body":body}
				return HttpResponse(request.POST['title'])

create 함수 수정 part4

nextId = 4 # line 4
topics = [
    {'id':1, 'title':'routing', 'body':'Routing is...'},
    {'id':2, 'title':'view', 'body':'View is...'},
    {'id':3, 'title':'model', 'body':'Model is...'}
]


@csrf_exempt # csrf 보안 방식을 끄는 명령어 csrf_exempt를 import해야함. 
def create(request):
		global nextId
		if request.method == "GET":
				article = '''
						<form action="/create/" method="post">
								<p><input type="text" name="title" placeholder="title"></p>
								<p><textarea name="body" placeholder="body"></textarea></p>
								<p><input type="submit"></p>
						</form>
				'''
				return HttpResponse(HTMLTemplate(article))
		elif request.method == "POST":
				title = request.POST['title']
				body = request.POST['body']
				newTopic = {"id":nextId, "title":title, "body":body}
				topics.append(newTopic)
				nextId += 1
				return HttpResponse(request.POST['title'])

create 함수 수정 part5

from django.shortcuts import render

nextId = 4 # line 4
topics = [
    {'id':1, 'title':'routing', 'body':'Routing is...'},
    {'id':2, 'title':'view', 'body':'View is...'},
    {'id':3, 'title':'model', 'body':'Model is...'}
]


@csrf_exempt # csrf 보안 방식을 끄는 명령어 csrf_exempt를 import해야함. 
def create(request):
		global nextId
		if request.method == "GET":
				article = '''
						<form action="/create/" method="post">
								<p><input type="text" name="title" placeholder="title"></p>
								<p><textarea name="body" placeholder="body"></textarea></p>
								<p><input type="submit"></p>
						</form>
				'''
				return HttpResponse(HTMLTemplate(article))
		elif request.method == "POST":
				title = request.POST['title']
				body = request.POST['body']
				newTopic = {"id":nextId, "title":title, "body":body}
				topics.append(newTopic)
				url = '/read/'+str(nextId)
				nextId += 1
				return redirect(url) # line1에 redirect import추가

🖇️ redirect & render

redirect

redirect(to, permanent = False, *args, **kwargs)

redirect는 위와 같은 파라미터를 가진다. to에는 어느 URL로 이동할지를 정하게 된다. 이 때, 상대 URL, 절대 URL 모두 가능하며 urls.pyname을 정의하고 이를 많이 사용한다. 단지 URL로 이동하는 것이기 때문에 render처럼 context값을 넘기지는 못한다.

render

render(request, template_name, context = None, content_type = None, status = None, using = None)

render는 위와 같은 파라미터들을 가진다. request와 template_name은 필수적으로 필요!! request는 위와 동일하게 작성하고, template_name은 불러오고 싶은 템플릿을 기재하면 된다. 쉽게 생각하면 화면에 html 파일을 띄운다고 생각하면 된다. 이 때 context로는 원하는 인자를, 즉 view에서 사용하던 파이썬 변수를 html 템플릿으로 넘길 수 있다. context는 딕셔너리형으로 사용하며 key값이 템플릿에서 사용할 변수이름, value값이 파이썬 변수가 된다.

render & redirect 차이 한 줄 정리

  • render: 템플릿을 불러옴
  • redirect: URL로 이동함

📑 참고자료

[HTTP] HTTP Request Method 종류와 설명
HTTP request method
Query String 쿼리스트링이란?
[간단정리]HTTP Request/Response 구조
[Network] HTTP Request/Response 란
HTTP headers
Django document

profile
능동적으로 행동함으로써 세상을 더 좋게 가꾸어가는 사람

0개의 댓글