0. views
context 와 return render() 들여쓰기 주의!!!!
def question_create(request):
form = POST 입력받은 폼 / 빈 폼 저장.
context = {'form': form}
return render()

{{ form.as_p }} 는 html 코드가 자동 생성되므로, 디자인 측면에서 제한이 많다. 수동폼으로
1. 폼 위젯과 레이블
class QuestionForm(forms.ModelForm):
class Meta:
model = Question
fields = ['subject', 'content']
# widgets = {
# 'subject': forms.TextInput(attrs={'class': 'form-control'}),
# 'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
# }

class Meta:
model = Question
fields = ['subject', 'content']
widgets = {
'subject': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
}

class Meta:
model = Question
fields = ['subject', 'content']
widgets = {
'subject': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
}
# subject, content 한글로 레이블
labels = {
'subject': '제목',
'content': '내용',
}
2. 폼 템플릿.html 에서 {{ form.as_p }} 대신, 폼을 수동으로 작성하자.
forms.py 에서 widgets 항목 삭제.
{% extends 'base.html' %}
{% block content %}
<div class="container">
<h5 class="my-3 border-bottom pb-2">질문등록</h5>
<form method="post">
{% csrf_token %}
<!-- 오류표시 Start -->
{% if form.errors %}
<div class="alert alert-danger" role="alert">
{% for field in form %}
{% if field.errors %}
<div>
<strong>{{ field.label }}</strong>
{{ field.errors }}
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
<!-- 오류표시 End -->
<div class="mb-3">
<label for="subject" class="form-label">제목</label>
<input type="text" class="form-control" name="subject" id="subject"
value="{{ form.subject.value|default_if_none:'' }}">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" name="content"
id="content" rows="10">{{ form.content.value|default_if_none:'' }}</textarea>
</div>
<button type="submit" class="btn btn-primary">저장하기</button>
</form>
</div>
{% endblock %}
detail.html 답변 등록도 업그레이드 ( forms.py 사용 + 유효성으로 오류 표시 등)
<form action="{% url 'b2b:answer_create' q.id %}" method="post">
{% csrf_token %}
<input type="text" name="subject" id="subject">
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="댓글 등록">
</form>
views.py 도 forms.py 사용하는 방식으로
변경전)
def answer_create(request, question_id):
q = get_object_or_404(Question, pk=question_id)
q.answer_set.create(subject=request.POST.get('subject'), content=request.POST.get('content'),
create_date=timezone.now())
return redirect('b2b:detail', q.id)
삽질 많이 했다.... views.py 의 def answer_create 에서 return redirect('b2b:detail', question_id=q.id) 에서 삽질.
urls.py 에서, answer/<int:pk> 인데, views.py 에서 question_id 로 인자를 저장해서 redirect 하니 오류가 생겼다.
매개변수 값만 전달하면 오류가 안났을텐데... 아니면, pk = q.id 라던가
def answer_create(request, question_id):
q = get_object_or_404(Question, pk=question_id)
# q.answer_set.create(subject=request.POST.get('subject'), content=request.POST.get('content'), create_date=timezone.now())
if request.method == 'POST':
form = AnswerForm(request.POST)
if form.is_valid():
answer = form.save(commit=False)
answer.create_date = timezone.now()
answer.question = q
answer.save()
return redirect('b2b:detail', q.id)
# urls.py 의 detail 에서, /<int:pk>/ 이므로, pk=q.id 또는 매개변수로 q.id 만 써야한다.
else:
return HttpResponseNotAllowed('답변은 GET 방식 불가.')
# return redirect('b2b:detail', q.id)
# 'POST" 지만, form.is_valid()하지 않으면, 진행.
context = {'question': q, 'form': form}
return render(request, 'b2b:detail.html', context)
페이징
기존의 리스트(question_list = Question.objects.order_by('-create_date'))는 전체 리스트였다.
==> 페이지네이터( 기존의 전체 리스트 + get_page(page))
##views.py
def index(request):
# return HttpResponse("안녕하세요 ")
page = request.GET.get('page', '1')
question_list = Question.objects.order_by('-create_date')
paginator = Paginator(question_list, 10)
page_obj = paginator.get_page(page)
# 전체 리스트 --> 페이징
# context = {'question_list': question_list}
context = {'question_list': page_obj}
return render(request, 'b2b/question_list.html', context)
## template
{% extends 'base.html' %}
{% block content %}
<div class="container my-3">
<table class="table">
<thead>
<tr class="table-dark">
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
{% if question_list %}
{% for question in question_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>
<a href="{% url 'pybo:detail' question.id %}">{{ question.subject }}</a>
</td>
<td>{{ question.create_date }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="3">질문이 없습니다.</td>
</tr>
{% endif %}
</tbody>
</table>
<!-- 페이징처리 시작 -->
<ul class="pagination justify-content-center">
<!-- 이전페이지 -->
{% if question_list.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ question_list.previous_page_number }}">이전</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">이전</a>
</li>
{% endif %}
<!-- 페이지리스트 -->
{% for page_number in question_list.paginator.page_range %}
{% if page_number >= question_list.number|add:-5 and page_number <= question_list.number|add:5 %}
{% if page_number == question_list.number %}
<li class="page-item active" aria-current="page">
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
</li>
{% endif %}
{% endif %}
{% endfor %}
<!-- 다음페이지 -->
{% if question_list.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ question_list.next_page_number }}">다음</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">다음</a>
</li>
{% endif %}
</ul>
<!-- 페이징처리 끝 -->
<a href="{% url 'pybo:question_create' %}" class="btn btn-primary">질문 등록하기</a>
</div>
{% endblock %}
03-3 템플릿 필터 사용하기 :: add 대응하는 sub(빼기필터) 만들기
templatetags/pybo_filter.py
from django import template
register = template.Library()
@register.filter
def sub(value, arg):
return value - arg
## 템플릿에서 사용.
{% load pybo_filter %}
{{ question_list_paginator.count|sub:question_list.start_index|sub:forloop.counter0|add:1)
답변 개수 표시하기. / 카테고리 수 표시
'장고 > 점프투장고' 카테고리의 다른 글
댓글 수: {% if question.answer_set.count > 0 %} (0) | 2023.11.15 |
---|---|
로그인 로그아웃 구현 + 리다이렉트 URL ( config/urls.py ) (0) | 2023.11.15 |
urls.py <int:pk> <------- views.py : redirect(___, pk=question.id) (0) | 2023.11.14 |
폼 에러 표시. class , form.errors/field.label/field.errors (0) | 2023.11.13 |
테이블 모양 / 부트스트랩 (0) | 2023.11.12 |
settings.py : templates , static, media_url (0) | 2023.11.12 |
폼 + 상품의 총 구매수 {{ q.answer_set.count }} 출력 (0) | 2023.11.12 |
NoReverseMatch at /b2b/2/ Reverse for '....' with arguments 오류 (1) | 2023.11.12 |
댓글