18.Django(장고) - ecommerce 프로젝트 - 게시판 글등록-폼 적용-2(수동폼 적용)

JungSik Heo·2024년 12월 6일

1.폼 위젯 적용해 보기

이제 게시글 등록은 잘 되지만 한 가지 아쉬운 점이 있다. 우리는 화면을 더 아름답게 꾸밀 수 있는 부트스트랩을 준비해 두었다. 그러나 {{ form.as_p }} 태그는 HTML 코드를 자동으로 생성하기 때문에, 부트스트랩 스타일을 직접 적용할 수 없다.

해결방법은 없을까?

완벽하지는 않지만, 다음처럼 QuestionForm을 조금 수정하면 어느 정도 해결이 가능하다.

boards\forms.py

class PostForm(forms.ModelForm):
    class Meta:
        model = Post  # 사용할 모델
        fields = ['title', 'content']
        widgets = {
            'subject': forms.TextInput(attrs={'class': 'form-control'}),
            'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
        } 

아래를 추가 해보자

        labels = {
            'title': '제목',
            'content': '내용',
        }  

2.수동 폼 작성(기존폼 단점)

{{ form.as_p }}를 사용하면 빠르게 템플릿을 만들 수 있지만, HTML 코드가 자동으로 생성되기 때문에 디자인 측면에서 많은 제한이 생긴다. 예를 들어, 폼 엘리먼트 내에 특정 태그를 추가하거나 필요한 클래스를 적용하는 작업에 제약이 따른다. 또한, 디자인 영역과 서버 프로그램 영역이 혼재되어 웹 디자이너와 개발자의 역할 분리가 모호해질 수 있다.

이번에는 폼을 이용해 자동으로 HTML 코드를 생성하지 않고, 직접 HTML 코드를 작성하는 방법을 사용해 보자. 우선, 수작업 시 필요 없는 widget 속성을 제거하자.

boards\forms.py

아래와 같이 삭제

그리고 질문 등록 템플릿을 다음과 같이 수정하자.

templates\boards\post_form.html

{% extends 'boards/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="title" id="title" value="{{ form.title.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 %}

{{ form.as_p }}로 자동으로 생성되는 HTML 대신 제목과 내용에 해당되는 HTML코드를 직접 작성했다. 그리고 post_create 함수에서 form.is_valid() 가 실패할 경우 발생하는 오류의 내용을 표시하기 위해 오류를 표시하는 영역을 추가했다.

제목(title) 항목의 value에는 {{ form.title.value|default_if_none:'' }} 처럼 값을 대입해 주었는데 이것은 오류가 발생했을 경우 기존에 입력했던 값을 유지하기 위함이다. |default_if_none:''의 의미는 폼 데이터(form.title.value)에 값이 없을 경우 None 이라는 문자열이 표시되는데 None 대신 공백으로 표시하라는 의미의 템플릿 필터이다.

장고의 템플릿 필터는 |default_if_none:'' 처럼 | 기호와 함께 사용된다.

"내용"에 아무런 값도 입력하지 않았기 때문에 "내용"을 입력하라는 오류메시지를 볼 수 있다. 그리고 "제목"에 입력했던 "TEST"는 사라지지 않고 계속 유지되는 것도 확인할수 있다

답변 등록 폼적용 해 보기

이번에는 질문 등록에 장고 폼을 적용한 것처럼 답변 등록에도 장고 폼을 적용해 보자. 답변을 등록할 때 사용할 ReplyForm을 boards/forms.py 파일에 다음과 같이 작성하자.

boards\forms.py

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment  # 사용할 모델
        fields = ['content']
        labels = {
            'content': '댓글',
        }   

boards\urls.py
아래를 추가

path('reply/create/<int:post_id>/', views.comment_create, name='reply_create'),

boards\views.py 추가

def comment_create(request,post_id):
    """
    댓글 등록
    """
    post = get_object_or_404(Post, pk=post_id)
    if request.method == 'POST':
        form = CommentForm(request.POST)
        
        if form.is_valid(): # 폼이 유효하다면
            comment = form.save(commit=False) # 임시 저장하여 post 객체를 리턴받는다.
            #post.created_at = timezone.now()# 실제 저장을 위해 작성일시를 설정한다.
            comment.post = post
            comment.save()# 데이터를 실제로 저장한다.
            return redirect('boards:index', post_id=post.id)
    else:
        return HttpResponseNotAllowed('Only POST is possible.')

    context = {'post':post,'form': form}
    return render(request, 'boards/post_form.html', context)

하지만 답변 등록은 POST 방식만 사용되기 때문에 GET 방식으로 요청할 경우에는 HttpResponseNotAllowed 오류가 발생하도록 했다.

templates\boards\post_detail.html

{% extends 'boards/base.html' %}
{% block content %}

<div class="container my-3">
  <!-- 부모글 -->
  <h2 class="border-bottom py-2">{{ post.title }}</h2>
  <div class="card my-3">
    <div class="card-body">
      <div class="card-text" style="white-space: pre-line;">{{ post.content }}</div>
      <div class="d-flex justify-content-end">
        <div class="badge bg-light text-dark p-2">
          {{ post.created_at }}
        </div>
      </div>
    </div>
  </div>

  <!-- 댓글목록 -->
  <h5 class="border-bottom my-3 py-2">{{post.comment_set.count}}개의 댓글이 있습니다.</h5>
  {% for comment in post.comment_set.all %}
    <div class="card my-3">
      <div class="card-body">
        <div class="card-text" style="white-space: pre-line;">{{ comment.content }}</div>
        <div class="d-flex justify-content-end">
          <div class="badge bg-light text-dark p-2">
            {{ comment.created_at }}
          </div>
        </div>
      </div>
    </div>
  {% endfor %}

  <!-- 댓글등록 -->
  {% comment %} <form action="{% url 'boards:reply_create' post.id %}" method="post">
    {% csrf_token %}
    <textarea name="content" id="content" rows="15"></textarea>
    <input type="submit" value="댓글등록">
  </form> {% endcomment %}
  <form action="{% url 'boards:reply_create' post.id %}" method="post" class="my-3">
    {% 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="content" class="form-label">답변내용</label>
        <textarea name="content" id="content" class="form-control" rows="10"></textarea>
    </div>
    <input type="submit" value="댓글등록" class="btn btn-primary">
</form>
</div>
{%endblock%}

profile
쿵스보이(얼짱뮤지션)

0개의 댓글