Framework/Django

TIL-장고 네번째 튜토리얼(Django tutorial#4)

청렴결백한 만능 재주꾼 2020. 5. 9. 17:10
반응형

장고 이용해서 뭐 만드는거 꽤나 복잡하다~하지만 뭐 크게 문제 될 건 없다. 구조랑 왔다갔다하고 모듈이나 클래스들을 몰라서 그렇지 대충 뭐하는 건지만 알면 되지 않겠는가 ,,, 이런 긍정의 마음을 갖기 전까지 많은 고생이 있었다... 오늘도 화이팅하자 갈길 머니까

 


####Finally we are here #4 django tutorial!! 

##Write a mininal form

바로 전 튜토리얼에서 했던 template안에 detail.html을 대충 수정했었는데 이번에 제대로 받았다. 

 


polls/templates/polls/detail.html

 

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

 

<form action="{% url 'polls:vote' question.id %}" method="post">

{% csrf_token %}

{% for choice in question.choice_set.all %}

      <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">

      <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>

{% endfor %}

<input type="submit" value="Vote">

</form>


일단 집어 넣었다. 무슨말인지는 설명이 나오는데... 대충 짚고 가자 ...

 

+ 각질문 선택 항목에 대한 라디오 버튼을 표시하고 클릭할 수 있게 한다.  (참고 왼쪽 사진!!) 버튼 옆 value는 질문과 연관된 선택 항목의 ID이다. 각 버튼의 name은 "Choice"이다.

+ 세번째 단락에서 form action에서 method="POST"를 하였다. POST는 GET에 반대되는 개념으로 입력하고 제출되었을 때 서버 쪽 데이터가 바뀌어 진다. 서버 쪽 데이터를 바꿀 form을 쓰고 싶다면 POST를 써야한다. 이건 쟝고에 국한된 정보가 아니고 웹개발자에게 유용한 팁이다. 

+ forloop.counter는 For태그가 반복 한 횟수를 나타낸다.

+ POST form을 쓸 때에는 CRSF(Cross Site Request Forgeries)를 조심해야 한다. 하지만 장고에서는 이런 것을 보호해준다. 걱정 ㄴㄴ.  내부 URL 쓸 때에 csrf_token 을 써라~~

 

vote()함수를 가상으로 만들어 주었다. polls/views.py에 추가를 한다.


* polls/views.py

from django.http import HttpResponse, HttpResponseRedirect

from django.shortcuts import get_object_or_404, render

from django.urls import reverse

 

from .models import Choice, Question

def vote(request, question_id):

      question = get_object_or_404(Question, pk=question_id)

      try: selected_choice = question.choice_set.get(pk=request.POST['choice'])

     

      except (KeyError, Choice.DoesNotExist):

 

      """Redisplay the question voting form."""

 

      return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", })

      else: selected_choice.votes += 1 selected_choice.save()

 

      """Always return an HttpResponseRedirect after successfully dealing

      with POST data. This prevents data from being posted twice if a

      user hits the Back button."""

 

      return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) *


여기서 아직 우리가 다루지 못한 몇가지가 있다.
+ request.POST 는 키로 전송된 자료에 접근할 수 있도록 해주는 사전과 같은 객체다. (try부분에 있다. ) 여기 request.POST['choice']는 선택된 설문의 ID를 문자열로 반환한다.**request.POST의 값은 항상 문자열이다.** 장고에서는 같은 방법으로 request.GET도 제공한다.

 

+ POST자료에 request.POST['choice']의 choice가 없으면 KeyError가 일어난다. 위의 코드는 KeyError를 체크하고, choice가 주어지지 않은 경우에는 에러 메시지와 함게 설문조사 폼을 다시 보여줌.

 

+ 설문지의 수가 증가한 이후에, 코드는 일반 HttpResponse가 아닌 HttpResponseRedirect를 반환하고, HttpResponseRedirect는 하나의 인수를 받는다.. 그 인수는 사용자가 재전송할 URL 이다. 

 

+ HttpResponseRedirect 안에 reverse()함수를 사용하고 있다. 이 함수는 view 함수에서 URL을 하드코딩하지 않도록 도와준다. 이 함수를 호출하면 urlpatterns에서 name 이 results인 것을 찾게 될 것이고 '/polls/1/results/'를 반환하게 될 것이다.

 


reverse()

reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)

viewname : can be a URL pattern name  or  the callable view object.


ex) 

urls.py
path('archive/', views.archive, name='news-archive') 가 있다고 치고,

*reverse('news-archive')* 로 쓸 수 있다.

하지만 이것보단 

*reverse(views.archive)*가 좋겠다.

URL이 인자를 받아야 한다면 

*HttpResponseRedirect(reverse('arch-summary', args=[1945]))*

로 쓸 수도 있다.

 

키워드 인자일 경우

reverse('admin:app_list', kwargs = {'app_label' : 'auth'})

 


 


위에서 한것처럼 이제 vote를 끝내면 results로 보낸다.  results를 설정해보자 

polls/views.py 가서

위에 모듈들은 놔두고

* def results(request, question_id):

      question = get_object_or_404(Question, pk=question_id)

      return render(request, 'polls/results.html', {'question': question}) * 

 

를 추가해준다.

Detail()뷰와 동일하다. 이제 템플릿 안에 results.html을 만든다.

 


polls/templates/polls/results.html

<h1>{{ question.question_text }}</h1>

<ul> {% for choice in question.choice_set.all %}

      <li>{{ choice.choice_text }} -- {{ choice.votes }}

            vote{{ choice.votes|pluralize }}

      </li>

{% endfor %}

</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>


대략 이렇게 하고 나면 사진 처럼 나온다! localhost:8000/polls 

정상 작동한다. 따라하는 것도 힘드네.

 

경쟁 상태(race condition)을 조심해야 한다. 문제 해결은 Avoiding race conditions using F()을 참고하라신다.

 

 

##제너릭 뷰 사용하기:코딩은 최소한으로 (Use generic views:Less code is better)

알쓸전컴블로그에서 퍼온 것:

_URL에서 전달 된 매개 변수에 따라 데이터베이스에서 데이터를 가져 오고 이것을 view에서 render 함수 등을 통해

템플릿에 리턴하는 기본 웹 개발의 일반적인 경우를 장고에서는 제너릭뷰를 제공하여 적은 코드로 사용할 수 있게 해준다._

 

쟝고 튜토리얼에 있는 것:

_URL에서 전달 된 매개 변수에 따라 데이터베이스에서 데이터를 가져 오는 것과 템플릿을 로드하고 렌더링 된 템플릿을 리턴하는 기본 웹 개발의 일반적인 경우를 나타냅니다. Django는 이런 매우 일반적인 경우를 위해 "제너릭 뷰"시스템이라는 지름길을 제공합니다._

 

구구의 개발공부 블로그:

  • URL에서 전달된 매개변수에 따라 데이터베이스에서 데이터를 가져오는 것과 템플릿을 로드하고 렌더링된 템플릿을 리턴하는 기본 웹 개발의 일반적인 경우를 제너릭 뷰 시스템이라는 지름길을 제공한다.
  • 제너릭 뷰는 일반적인 패턴을 추상화하여 코드를 줄일 수 있다.
  • 제너릭 뷰로 전환하려면 urls.py와 views.py의 수정이 필요하다.

 

이렇게 구구절절 비슷한 말만 있어서 이해가 당장 어려웠지만!! 나만의 개념을 만들기 위해 밑에 것들을 먼저 보는게 좋을 것 같다.

일단 튜토에서는 일부러 어렵게 views를 작성하게 의도했고 쉽게 갈 수 있는 법을 알려준다. 어느 학원이나 비슷한 방법으로 가르치는 것 같다. 

 

제너릭뷰를 사용하여 쉽게 가는 법, 3가지 해야할 행동

 + URLconf를 변환하기

 + 불필요한 오래된보기 중 일부를 삭제

 + Django의 제너릭 뷰를 기반으로 새로운 뷰 도입

###- URL conf

polls/urls.py 에서 path를 고친다. question_id를 primary key인 pk로 고친다. 그리고 views뒤에 덧붙인다. 오른쪽 그림처럼 대략 고치고 바로 views를 수정하러 가야한다.

 

polls/views.py에서 고칠 것이 많은데  urls에서 수정한 것 처럼 vote빼고 고치면 된다. index, detail, results를 수정한다.

 

중간 중간 들어가는 대문자를 놓쳐서 서버가동했을 때에 오류가 많이 떴었다. 타이핑에 신중을 한번 더 더해야겠다는 생각을 한번 더 되새긴다.

 

간략히 옛버전과 적용된 버전의 차이를 그림으로 확인할 수 있다.

 

 

왼쪽 : old version , 오른쪽 : generic view 적용 후

얼핏 큰 차이는 없어 보이는 것은 template의 경로를 우리가 지정해야 되서 그렇다. 원래 템플릿을 쟝고에서 제너릭 뷰(Generic View)를 쓸 때에 <app name>/<model_name>_detail.html 같은 식으로 형식을 사용한다. 근데 우리는 지금까지 그렇게 하지 않았기 때문에 저렇게 지정해줬고 아니면 파일이름을 바꿔도 된다.

 

두가지의 제너릭 뷰를 확인할 수 있다.

ListView

DetailView

이 두view는 각각 "개체 목록 표시" 및 "특정 개체 유형에 대한 세부 정보 페이지 표시"개념을 추상화 한다.

 - 각 제너릭 뷰는 어떤 모델이 적용될 것인지를 알아야 한다. model 속성을 사용하여 제공됨

 - DetailView 제너릭 뷰는 URL에서 캡쳐 된 기본키 값이 ''Pk"\ 라고 기대하기 때문에 ''question_id를 제너릭 뷰를 위해 pk로 변경한다.

 

 

이로써 4장을 마치는데 내가 생각한 제너릭 뷰의 개념

말 그대로 일반적인 뷰라고 생각한 후 자주 쓰고 귀찮게 돌아갈 필요없는 것들에 대해 간단히 View를 만들 수 있게 해주는 것이다. 똑같은 말인가..? 그냥 편의를 위해 반복할 것들을 줄여준 것. 잘 알아놓으면 다음에 편하게 살 수 있다.

반응형