카테고리 없음

[Django] 1주차_3_장고 기본 요소 2

신형철 2022. 5. 8. 12:40

이 글은 점프 투 장고를 참고하여 작성하였습니다.

작성자 : 신형철

개발환경은 Python, PyCharm입니다. 

 

 

1. 조회와 템플릿

from django.shortcuts import render
from .models import Question


def index(request):
    question_list = Question.objects.order_by('-create_date')
    context = {'question_list': question_list}
    return render(request, 'pybo/question_list.html', context)

우선 위와 같은 코드를 pybo/view.py에 작성해주어 질문 목록을 불러올 수 있도록 한다. 이후에 템플릿을 설정을 해주는데 템플릿은 파이썬 데이터를 읽어서 이용할 수 있는 HTML파일이다.

다음과 같이 템플릿을 사용할 수 있도록 템플릿을 저장할 폴더를 생성해준다. 

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        ...
    },
]

저장 폴더를 생성해줄 때 mysite/templates에 위치하게 조심해 생성해준다. 여러 앱의 화면을 구성하는 공통 템플릿은 다음과 같이 하나의 폴더에서 관리해주는 것이 편하다.

<!-- projects/mysite/templates/pybo/question_list.html 파일 경로 -->

{% if question_list %}
    <ul>
    {% for question in question_list %}
        <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>질문이 없습니다.</p>
{% endif %}

위에 써준 파일 경로에 다음과 같은 html파일을 작성한다. 그러고나서 서버를 돌리면 다음과 같이 각 question의 제목이 나타날 것이다.

여기까지 했을 때 각 질문을 선택하면 url연결이 되어 있지 않기 때문에 페이지를 연결할 수 없다는 오류가 나올 것이다.

그렇기 때문에 pybo/urls.py에 다음과 같이 path를 추가해준다.

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index),
    path('<int:question_id>/', views.detail),
]

위와 같이 path를 추가해주고, views.detail에 대한 함수를 만들어주기 위해서 pybo/views.py에 detail함수를 만들어 준다.

def detail(request, question_id):
    question = Question.objects.get(id=question_id)
    context = {'question': question}
    return render(request, 'pybo/question_detail.html', context)

그러고 나서 템플릿에 question_detail.html을 만들어 결과를 출력해준다.

<h1>{{ question.subject }}</h1>
<div>
    {{ question.content }}
</div>

이제 위의 각 질문을 선택하면 다음과 같은 화면이 출력될 것이다.

2. URL 별칭

url을 위와 같이 설정해주면 링크를 수정할 때 하나하나 전부 변경해줘야 하기 때문에 별칭을 사용해 1:1 매핑을 해주는 것이 좋다. 다음과 같이 각각 index, detail에 대한 별칭을 지정해주고, app_name을 지정해준다.

from django.urls import path

from . import views

app_name = 'pybo'

urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
]

이제 이 별칭을 사용해줘야 한다.

...
<li><a href="{% url 'pybo:detail' question.id %}">{{ question.subject }}</a></li>
...

question_list.html에 위와 같이 url을 매핑해준다.

 

3. 데이터 저장

...
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
{% csrf_token %}
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변등록">
</form>

question.html파일 뒷부분에 위의 코드를 추가해 답변등록이 가능한 텍스트 칸을 생성해준다. {% csrf_token %}은 보안에 관련된 항목으로 꼭 잊지말고 작성해준다.

urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('answer/create/<int:question_id>/', views.answer_create, name='answer_create'),
]

pybo/urls.py에 다음과 같이 답변에 대한 url을 매핑해준다.

from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Question

...
...

def answer_create(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    question.answer_set.create(content=request.POST.get('content'), create_date=timezone.now())
    return redirect('pybo:detail', question_id=question.id)

url을 매핑했다면 view.py파일에 답변을 가져올 함수를 생성해준다. FK로 연결된 것을 이용해 question의 값을 이용해 답변을 가져올 수 있다. 마찬가지로 question_detal.html에 다음 코드를 추가해 답변등로 외에 조회를 할 수 있도록 만든다.

...
	{{ question.content }}
</div>
<div>
    <ul>
    {% for answer in question.answer_set.all %}
        <li>{{ answer.content }}</li>
    {% endfor %}
    </ul>
</div>
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
...

여기까지 잘 마쳤다면 다음과 같은 화면이 나타날 것이다.

 

4. 스태틱

이렇게 열심히 만들었지만 솔직히 디자인이 상당히 구리다. 이것을 보완하기 위해서 스타일시트인 CSS를 등록해준다. 스타일 시트는 스태틱 폴더에 저장이 되는데 이를 사용하기 위해서 config/settings.py에 다음 코드르 입력해주고, 폴더도 생성해준다.

...
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / 'static',
]
...

static폴더를 만들어주고, 그 안에 css파일을 만들어준다. 그리고 간단하게 스타일을 지정해주었다.

textarea {
    width:100%;
}

input[type=submit] {
    margin-top:10px;
}

이 스타일을 사용해주기 위해서 question.detail의 제일 상단부분에 다음과 같은 코드를 추가해주었다.

{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'style.css' %}">
<h1>{{ question.subject }}</h1>
<div>
    {{ question.content }}
</div>
...

여기까지 완료했다면 다음과 같은 답변 페이지가 완성이 된다.