from django.http import HttpResponse
# 추가
from .models import *
from django.shortcuts import render
# 수정
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5] # 가장 최근에 생성된 질문 5개
context = {'first_question' : latest_question_list[0]}
return render(request, 'polls/index.html', context) # request에 대해서 polls/index.html을 렌더링하고 인자로 context를 넘겨줌
def some_url(request):
return HttpResponse("Some URL")
polls에 templates/polls 디렉토리 생성하고 안에 index.html 생성
polls/templates/polls/index.html
<ul>
<li>{{first_question}}</li>
</ul>
# 중괄호를 두 번 씌운 이유 : 템플릿 엔진이나 서버 사이드 코드에서 해당 중괄호 안에 있는 변수 first_question의 값을 가져와 실제 데이터로 채우기 위해
출력 결과
{% %}
사용{% if questions %}
<ul>
{% for question in questions %}
<li>{{question}}</li>
{% endfor %}
</ul>
{% else %}
<p>no questions</p>
{% endif %}
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'), # url 뒤에 비어서 들어올 경우 views.index로 보내고 이름은 index로 설정
path('<int:question_id>/', views.detail, name='detail'), # url이 'polls/숫자'로 입력되면 views.detail로 전송하고 question_id로 전달
path('some_url', views.some_url),
]
from django.http import HttpResponse
from .models import *
from django.shortcuts import render
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'questions' : latest_question_list}
return render(request, 'polls/index.html', context)
def some_url(request):
return HttpResponse("Some URL")
# 추가
def detail(request, question_id):
question = Question.objects.get(pk=question_id) # 해당 question_id를 갖는 Question을 찾아 question에 저장
return render(request, 'polls/detail.html', {'question':question}) # polls/detail.html로 렌더링
templates/polls 안에 detail.html 생성
polls/templates/polls/detail.html
<h1>{{question.question_text}}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{choice.choice_text}}</li>
{% endfor %}
</ul>
결과
from django.urls import path
from . import views
# 해당 앱의 이름 설정.
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('some_url', views.some_url),
path('<int:question_id>/', views.detail, name='detail')
]
{% if questions %}
<ul>
{% for question in questions %}
<li><a href="{% url 'polls:detail' question.id %}">{{question.question_text}}</a></li>
{% endfor %}
</ul>
{% else %}
<p>no questions</p>
{% endif %}
polls/views.py 수정
from django.http import HttpResponse
from .models import *
from django.shortcuts import render
# 추가
from django.http import Http404
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'questions' : latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
# 추가
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question':question})
def some_url(request):
return HttpResponse("Some URL")
더 간편한 방법 - get_object_or_404
from django.http import HttpResponse
from .models import *
from django.shortcuts import render, get_object_or_404
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'questions' : latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
# 추가
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question':question})
def some_url(request):
return HttpResponse("Some URL")
투표 기능 구현
<form action='#' method='post'>
<h1>{{question.question_text}}</h1>
{% 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>
<form action='#' method='post'>
<!-- token 추가 -->
{% csrf_token %}
<h1>{{question.question_text}}</h1>
{% 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>
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
# vote에 대한 경로 추가
path('<int:question_id>/vote/', views.vote, name='vote'),
]
polls/views.py
from django.http import HttpResponse
from .models import *
from django.shortcuts import render, get_object_or_404
# from django.http import Http404
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'questions' : latest_question_list}
return render(request, 'polls/index.html', context)
def some_url(request):
return HttpResponse("Some URL !!")
def detail(request, question_id):
"""
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
"""
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
# vote 추가
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
selected_choice = question.choice_set.get(pk=request.POST['choice'])
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:index'))
polls/templates/polls/detail.html
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<h1>{{question.question_text}}</h1>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
{% 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>
from django.http import HttpResponse, HttpResponseRedirect
from .models import *
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'questions' : latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question':question})
def some_url(request):
return HttpResponse("Some URL!!")
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
# selected_choice가 있으면 요청을 받고, 없으면 error message 출력
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
return render(request, 'polls/detail.html', {'question': question, 'error_message': '선택이 없습니다.'})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:index'))
투표를 하려고 하는데 서버에서 해당 선택이 DB에서 사라진 경우 : Choice.DoesNotExist
투표 후 value값을 넘겨주는데 해당 id를 가진 선택이 없는 경우 : id값 확인 필요
polls/views.py
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):
return render(request, 'polls/detail.html', {'question': question, 'error_message': f"선택이 없습니다. id={request.POST['choice']}"})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:index'))
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):
return render(request, 'polls/detail.html', {'question': question, 'error_message': f"선택이 없습니다. id={request.POST['choice']}"})
else:
# F : DB에서 읽기
selected_choice.votes = F('votes') + 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:index'))
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/vote/', views.vote, name='vote'),
path('<int:question_id>/result/', views.result, name='result'),
]
<h1>{{question.question_text}}</h1><br>
{% for choice in question.choice_set.all %}
<label>
{{ choice.choice_text }} -- {{choice.votes}}
</label>
<br>
{% endfor %}
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):
return render(request, 'polls/detail.html', {'question': question, 'error_message': f"선택이 없습니다. id={request.POST['choice']}"})
else:
selected_choice.votes = F('votes') + 1
selected_choice.save()
# 수정
return HttpResponseRedirect(reverse('polls:result', args=(question_id,)))
# 추가
def result(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/result.html', {'question' : question})
1.polls/admin.py
from django.contrib import admin
from .models import *
admin.site.register(Choice)
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
# 커스텀 모델
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('질문', {'fields' : ['question_text']}),
# ['collapse'] : 숨김 처리
('생성일', {'fields' : ['pub_date'], 'classes' : ['collapse']}),
]
readonly_fields = ['pub_date']
inlines = [ChoiceInline]
admin.site.register(Question, QuestionAdmin)
2.polls/admin.py
from django.contrib import admin
from .models import *
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('질문', {'fields' : ['question_text']}),
('생성일', {'fields' : ['pub_date'], 'classes' : ['collapse']}),
]
list_display = ('question_text', 'pub_date', 'was_published_recently')
readonly_fields = ['pub_date']
inlines = [ChoiceInline]
list_filter = ['pub_date']
search_fields = ['question_text', 'choice__choice_text']
admin.site.register(Question, QuestionAdmin)
polls/models.py
from django.db import models
from django.utils import timezone
import datetime
from django.contrib import admin
class Question(models.Model):
# verbose_name 옵션에 필드의 칼럼명 입력
question_text = models.CharField(max_length=200, verbose_name="질문")
pub_date = models.DateTimeField(auto_now_add=True, verbose_name="생성일")
# @admin.display 어노테이션으로 함수의 칼럼명 입력
@admin.display(boolean=True, description='최근생성(하루기준)')
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def __str__(self):
if self.was_published_recently():
new_badge = "New"
else:
new_badge = ''
return f'{new_badge} 제목: {self.question_text}, 날짜: {self.pub_date}'
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return f'[{self.question.question_text}]{self.choice_text}'