[django] 점프 투 장고 - 장고 기초 9, 10

Joy·2020년 6월 22일
1

Django | 점프투장고

목록 보기
11/22

템플릿 상속

표준 HTML구조가 되도록 템플릿을 수정하기

표준 html 구조는 html, head, body 테그를 포함하고 스타일시트는 head 안에.



템플릿 상속

html 작성 시 표준스타일로 수정하면, body 테그 외에는 모두 동일한 내용일 것임. -> 중복 발생
중복 피하고 시트명이 변경되거나 추가될 때 하나하나 수정할 필요 없도록 템플릿 상속(extend) 자용하기.

base.html

  • 템플릿 dir에 기본이 되는 틀 작성하기

  • emmet 코드를 이용해서 !를 텝하면 html 기본 구조 나옴

{% load static %}
<!doctype html>
<html lang="ko">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" type="text/css" href="{% static 'bootstrap.min.css' %}">
    <!-- pybo CSS -->
    <link rel="stylesheet" type="text/css" href="{% static 'style.css' %}">
    <title>Hello, pybo!</title>
</head>
<body>
<!-- 기본 템플릿 안에 삽입될 내용 Start -->
{% block content %}
{% endblock %}
<!-- 기본 템플릿 안에 삽입될 내용 End -->
</body>
</html>

body 태그 안의 {% block content %} 와 {% endblock %} 는 base.html을 상속한 템플릿에서 구현해야 하는 영역

question_list.html

  • 질문 리스트 페이지 코드 변경
    base.html 상속하는 문법 써주기 -> 상속받아 표준 html 문서로 바뀜
    block content ~ endblock 사이에는 본 페이지에만 쓰이는 내용 작성
{% extends 'base.html' %}
{% block content %}

#기존코드...

{% endblock %}

question_detail.html

  • 위와 마찬가지로 수정

style.css

부트스트랩 사용하면서 본 파일은 필요없어서 빈파일로 남기기.


질문 등록하는 기능 구현하기

질문등록

  • 목록 페이지에 질문 등록할 수 잇는 버튼 생성하기
    "질문 등록하기" 링크 {% url 'pybo:question_create' %} 를 추가

    url 추가

    링크가 추가되었으니까 urls.py에 url 매핑 추가

    path('question/create/', views.question_create, name='question_create')

    뷰 함수 추가

    매핑에 쓴 question_create 대로 views.py에 뷰 함수 추가로 작성.

from .forms import QuestionForm

def question_create(request):
    """
    pybo 질문등록
    """
    form = QuestionForm()
    return render(request, 'pybo/question_form.html', {'form': form})
  • QuestionForm은 질문을 등록하기 위해 사용할 장고 폼(Form)

    폼작성

    QuestionForm 작성
    [C:\projects\mysite\pybo\forms.py]
    from django import forms
    from pybo.models import Question

class QuestionForm(forms.ModelForm):
class Meta:
model = Question
fields = ['subject', 'content']


- QuestionForm은 Question이라는 모델과 연결된 폼이고 속성으로 subject와 content를 사용한다고 정의하였다.
> 장고의 폼: 일반 폼(forms.Form)과 모델 폼(forms.ModelForm)
모델폼 : 모델(Model)과 연결된 폼. 폼을 저장하면 연결된 모델의 데이터를 저장할 수 있음.
모델 폼은 class Meta 라는 내부(Inner) 클래스가 반드시 필요 - Meta 클래스에는 사용할 모델과 모델의 속성을 적어주어야 한다.

### 템플릿 작성
question_form.html 템플릿 작성

``` html
{% extends 'base.html' %}
{% block content %}
<div class="container">
   <h5 class="my-3 border-bottom pb-2">질문등록</h5>
   <form method="post" class="post-form my-3">
       {% csrf_token %}
       {{ form.as_p }}
       <button type="submit" class="btn btn-primary">저장하기</button>
   </form>
</div>
{% endblock %}
  • {{ form.as_p }} 의 form은 question_create 함수에서 전달된 QuestionForm의 객체 - 제목과 내용같은 폼 입력항목을 위한 HTML코드들을 자동으로 만들어 냄

    get 과 post

질문등록버튼 생성됨

qeustion/create 페이지 생성

  • {{ form.as_p }}로 자동 생성된 입력항목 subject와 content를 확인
  • question_create 함수에는 아직 값을 저장하는 코드가 작성 필요

views에서 question_create함수 수정

def question_create(request):
    """
    pybo 질문등록
    """
    # ---------------------------------------- [edit] ---------------------------------------- #
    if request.method == 'POST':
        form = QuestionForm(request.POST)
        if form.is_valid():
            question = form.save(commit=False)
            question.create_date = timezone.now()
            question.save()
            return redirect('pybo:index')
    else:
        form = QuestionForm()
    context = {'form': form}
    return render(request, 'pybo/question_form.html', context)
  • 화면에서 버튼 클릭 -> question/create 페이지가 get 방식으로 호출 -> 화면 호출.

  • 질문 등록 화면에서 저장하기 버튼-> question/create 페이지가 POST 방식으로 호출, 데이터 저장

  • POST 요청의 경우 QuestionForm은 request.POST를 사용하여 생성해야함 -> QuestionForm의 subject와 content에는 request.POST로 전달받은 데이터가 저장

  • is_valid : 전송된 입력 항목의 값들이 유효한지를 검사

  • commit=False 옵션: 폼에 연결된 모델을 저장하지 않고 생성된 모델 객체만 리턴



폼 위젯

페이지 깔끔하게 개선하기

  • {{ form.as_p }} 는 HTML코드가 자동으로 생성되기 때문에 부트스트랩을 적용할 수가 없다

  • QuestionForm을 조금 수정하면 어느정도 해결이 가능
    widgets 속성을 지정하면 폼 입력 항목에 부트스트랩의 클래스를 추가 가능


  • label 사용하면 다른 이름으로 쓸 수 있음

    수동 폼 작성

    {{ form.as_p }}를 사용하면 빠르게 템플릿을 만들 수 있는 장점이 있지만 HTML코드가 자동으로 생성되기 때문에 디자인적인 측면에서 많은 제한 - 태그 추가, 클래스 추가 어려움.

  • 폼 이용해서 직접 HTML 코드 작성하기

widget 제거

  • 탬플릿 수정
{% extends 'base.html' %}

{% block content %}
<div class="container">
    <h5 class="my-3 border-bottom pb-2">질문등록</h5>
    <form method="post" class="post-form my-3">
        {% csrf_token %}
        <!-- -------------------------------------- [edit] -------------------------------------- -->
        <!-- 오류표시 Start -->
        {% if form.errors %}
            <div class="alert alert-danger" role="alert">
            {% for field in form %}
                {% if field.errors %}
                <strong>{{ field.label }}</strong>
                {{ field.errors }}
                {% endif %}
            {% endfor %}
            </div>
        {% endif %}
        <!-- 오류표시 End -->
        <div class="form-group">
            <label for="subject">제목</label>
            <input type="text" class="form-control" name="subject" id="subject"
                   value="{{ form.subject.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="content">내용</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 %}

|default_if_none:''의 의미는 폼 데이터(form.subject.value)에 값이 없을 경우 None 이라는 문자열이 표시되는데 None 대신 공백으로 표시

만약 내용 입력 없이 저장시도하면 알림뜸. 제목에 쓴 건 그대로 유지

답변등록

  • form 에 추가
  • views에서 함수 수정
  • 템플릿도 오류를 표시하기 위한 영역 추가
 from pybo.models import Question, Answer

class AnswerForm(forms.ModelForm):
    class Meta:
        model = Answer
        fields = ['content']
        labels = {
            'content': '답변내용',
        }
def answer_create(request, question_id):
    """
    pybo 답변등록
    """
    question = get_object_or_404(Question, pk=question_id)
    if request.method == 'POST':
        form = AnswerForm(request.POST)
        if form.is_valid():
            answer = form.save(commit=False)
            answer.create_date = timezone
            answer.question = question
            answer.save()
            return redirect('pybo:detail', question_id=question_id)

        else:
            form = Answerform()
        context = {'question' : question, 'form': form}
        return render(request, 'pybo/question_detail.html', context)
<form action="{% url 'pybo:answer_create' question.id %}" method="post" class="my-3">
    {% csrf_token %}
    <!-- -------------------------------------- [edit] -------------------------------------- -->
    {% if form.errors %}
    <div class="alert alert-danger" role="alert">
    {% for field in form %}
        {% if field.errors %}
        <strong>{{ field.label }}</strong>
        {{ field.errors }}
        {% endif %}
    {% endfor %}
    </div>
    {% endif %}

profile
roundy

0개의 댓글