장고 이용해서 뭐 만드는거 꽤나 복잡하다~하지만 뭐 크게 문제 될 건 없다. 구조랑 왔다갔다하고 모듈이나 클래스들을 몰라서 그렇지 대충 뭐하는 건지만 알면 되지 않겠는가 ,,, 이런 긍정의 마음을 갖기 전까지 많은 고생이 있었다... 오늘도 화이팅하자 갈길 머니까
####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를 수정한다.
중간 중간 들어가는 대문자를 놓쳐서 서버가동했을 때에 오류가 많이 떴었다. 타이핑에 신중을 한번 더 더해야겠다는 생각을 한번 더 되새긴다.
간략히 옛버전과 적용된 버전의 차이를 그림으로 확인할 수 있다.
얼핏 큰 차이는 없어 보이는 것은 template의 경로를 우리가 지정해야 되서 그렇다. 원래 템플릿을 쟝고에서 제너릭 뷰(Generic View)를 쓸 때에 <app name>/<model_name>_detail.html 같은 식으로 형식을 사용한다. 근데 우리는 지금까지 그렇게 하지 않았기 때문에 저렇게 지정해줬고 아니면 파일이름을 바꿔도 된다.
두가지의 제너릭 뷰를 확인할 수 있다.
ListView
DetailView
이 두view는 각각 "개체 목록 표시" 및 "특정 개체 유형에 대한 세부 정보 페이지 표시"개념을 추상화 한다.
- 각 제너릭 뷰는 어떤 모델이 적용될 것인지를 알아야 한다. model 속성을 사용하여 제공됨
- DetailView 제너릭 뷰는 URL에서 캡쳐 된 기본키 값이 ''Pk"\ 라고 기대하기 때문에 ''question_id를 제너릭 뷰를 위해 pk로 변경한다.
이로써 4장을 마치는데 내가 생각한 제너릭 뷰의 개념은
말 그대로 일반적인 뷰라고 생각한 후 자주 쓰고 귀찮게 돌아갈 필요없는 것들에 대해 간단히 View를 만들 수 있게 해주는 것이다. 똑같은 말인가..? 그냥 편의를 위해 반복할 것들을 줄여준 것. 잘 알아놓으면 다음에 편하게 살 수 있다.
'Framework > Django' 카테고리의 다른 글
TIL-장고 튜토리얼#6(Django tutorial #6) (0) | 2020.05.11 |
---|---|
TIL-장고 튜토리얼 #5..(Django tutorial #5) (0) | 2020.05.11 |
TIL-장고 튜토리얼 3번째 (#3 Django tutorial) (0) | 2020.05.07 |
TIL-쟝고 튜토리얼 탐험기02(Explore Django tutorial02)-장고 설계 철학, Polls.app 만들기 (0) | 2020.05.01 |
TIL-쟝고 튜토리얼01 탐험기(Explore Django tutorial01) (0) | 2020.04.29 |