query paramter : url의 ? 뒤의 파라미터
path parameter : url 사이에 있는 파라미터. 파라미터 타입을 정의한다. 이 규칙의 예는 아래와 같다.
int : 정수형 숫자
str : 모든 문자열
slug : -(하이픈)이나 _(언더스코어)를 포함한 영숫자, 문자열
먼저 html에서 두가지 방법의 요청을 확인해보자.
<!-- 하드코딩-->
<li><a href="/gogo/{{q.id}}/">{{q.question_text}}</a></li>
<!-- 소프트코딩 -->
<li><a href="{% url 'detail' q.id%}">{{q.question_text}}</a></li>
소프트 코딩 부분에서의 detail은 urls의 name(별명).
예를 들면 /gogo/2/ 와 같은 요청을 보내고, 이를 urls에서 받을땐 아래처럼 사용한다.
urlpatterns = [
path('<int:question_id>/',views.DetailFunc,name='detail'), #/gogo/1또는2/
]
다음 views에서 넘어온 데이터를 사용할땐
def DetailFunc(request,question_id): #<int:question_id>
'''
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404('Questrion does not exist!')
'''
question = get_object_or_404(Question,pk=question_id) #위의 try를 shortcut으로 함축
for cho in question.choice_set.all(): #오브젝트지정 후 전부 가져옴
print(cho.choice_text)
return render(request, 'detail.html',{'question':question})
이 반환값을 html에서 받을때.
<body>
<H2>{{question}}</H2>
<!-- http://localhost/gogo/1/vote/?choice=1 -->
<form action="{% url 'vote' question.id %}" method="post">{% csrf_token %}
{% for cho in question.choice_set.all %}
<!-- 인덱싱 -->
<input type="radio" name="choice" id="choice{{forloop.counter}}" value="{{cho.id}}">
<label for="choice{{forloop.counter}}">{{cho.choice_text}}</label>
{% endfor %}
<br>
<input type="submit" value="투표확인">
</form>
</body>
question.choice_set.all
은 파이썬 코드 question.choice_set.all()로 변환됨. 이는 iterable 객체를 반환하게 됨여기서 /gogo/2/vote?choice=1
을 위한 url매핑을 한번 더했다. 주석의 형태를 띄는 url를 만드는 것이 목적. urls에 vote별명을 받기 위한 코드를 추가했다.
path('<int:question_id>/vote',views.VoteFunc,name='vote'), #/gogo/1또는2/vote
이에 해당하는(vote요청) views 함수
def VoteFunc(request,question_id):
question = get_object_or_404(Question,pk=question_id)
try:
sel_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError,Choice.DoesNotExist):
return render
(request, 'detail.html',{'question':question,'error_msg':'1개의 항목을 꼭 선택하세요'})
sel_choice.votes += 1 #sel_choice : Choice 테이블
sel_choice.save() #투표수 갱신
# reverse() : 매핑되었던 url 패턴으로부터 url String 얻기 (/gogo/1/results/)
return HttpResponseRedirect(reverse('results',args=(question_id,)))
POST요청을 get하여 파라미터를 받고, question_id는 항상 따라다니며 알맞는 링크를 만든다.
get_object_or_404
short cut으로 질문 id에 맞는 객체를 받고, POST로 받은 파라미터를 이용해 선택항목에 대한 객체를 받았다.
reverse() 함수의 용도를 잘 기억하자.
결과 확인을 위한 result.html / views. 리다이렉트로 return
path('<int:question_id>/results/',views.ResultFunc,name='results'), #/gogo/1또는2/results
def ResultFunc(request,question_id):
question = get_object_or_404(Question,pk=question_id)
return render(request,'result.html',{'question':question})
HTML
<h2>{{question.question_text}}</h2>
결과 : <br/>
{% for cho in question.choice_set.all %}
<li>
{{cho.choice_text}} - {{cho.votes}} 표
</li>
{% endfor %}
<a href="{% url 'detail' question.id %}">같은 항목 다시 투표</a>