본문 바로가기

Django/Django 기초

[Django] 2 - 5. URL과 네임스페이스, 2 - 6. 데이터 저장

이전포스트

 

[Django] 1. 개발 환경 설정 https://wroni.tistory.com/4

[Django] 2 - 1. URL과 View https://wroni.tistory.com/5

[Django] 2 - 2. 모델 https://wroni.tistory.com/6

[Django] 2 - 3. 장고 관리자 https://wroni.tistory.com/7

[Django] 2 - 4. 조회와 템플릿 https://wroni.tistory.com/8

 


2 - 5. URL과 네임스페이스

 

1. URL과 하드코딩

 

파일 : C:\projects\mysite\pybo\templates\question_list.html

<li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>

 

question_list.html의 질문 상세를 위한 URL 링크다. 이러한 URL 링크는 웹 프로그램이 발전할 때마다 수정될 가능성이 크다.

 

http://localhost:8000/pybo/question/2 또는

http://localhost:8000/pybo/2/question 과 같이 바뀔 수 있다. 

 

URL 링크 구조가 자주 바뀌게 되면 이에 맞춰서 자주 수정해주어야 한다. 이러한 불필요한 일을 만들지 않기 위해 URL에 대한 실제 링크 대신 링크의 주소가 매핑되어 있는 별칭을 사용하자.

 

 

2. URL 별칭

 

실제 링크 대신 별칭을 사용하기 위해 URL 매핑에 name 속성을 부여하자

 

파일 : C:\projects\mysite\pybo\urls.py

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

 

path에 index라는 name과 detail이라는 name을 부여하였다.

 

템플릿에서 URL 별칭을 사용하려면, pybo/urls.py 파일을 변경하면 된다.

 

파일 : C:\projects\mysite\templates\pybo\question_list.html

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

 

하드코딩 되어 있던 /pybo/{{ question.id }} 링크가 {% url 'detail' question.id %}로 변경되었다. 

 

여기서 question_id는 URL 매핑에 정의된 <int:question_id>에 전달해야 하는 값이다.

 

 

3. URL 네임스페이스

 

우리는 pybo 앱 하나만 사용 중이지만 pybo 앱 이외에도 다른 앱이 프로젝트에 추가될 수도 있다.

그런데 서로 다른 앱에서 동일한 URL 별칭을 사용하면 중복이 발생한다.

 

중복 상황을 피하기 위해 pybo/urls.py 파일에 네임스페이스를 의미하는 app_name 변수를 지정하자.

 

파일 : C:\projects\mysite\pybo\urls.py

 

app_name = 'pybo'

 

이제 수정하고 웹 서버를 구동시켜 보자.

 

 

앗... question_list 가서 URL 별칭에 네임스페이스를 지정해주자

 

파일 : C:\projects\mysite\templates\pybo\question_list.html

 

위에 코드처럼 pybo: 만 추가하면 된다. detail 앞에 pybo라는 네임스페이스를 붙여주었다.

 


2 - 6. 데이터 저장

 

1. 답변등록 폼

 

답변을 저장할 수 있는 폼을 추가해보자. 질문 상세 템플릿을 수정하자.

 

파일 C:\projects\mysite\templates\pybo\question_detail.html

<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>

 

답변등록을 제출하도록 submit 버튼을 추가하였다. 답변 저장을 위한 URL은 form 태그에 action 속성에

{% url 'pybo:answer_create' question.id %}로 지정하였다.

 

{% csrf_token %}은 보안에 관한 항목으로 form으로 전송한 데이터가 실제 웹 페이지에서 작성한 데이터인지 판단하는 역할을 한다

form 바로 밑에 항상 {% csrf_token %} 태그를 위치시키자.

 

 

2. URL 매핑

 

질문 상세 템플릿을 고쳤으면, 상세 페이지를 요청해보자. 

 

 

answer_create 별칭을 찾을 수 없다는 오류가 뜬다.

위에서 질문 상세 템플릿에 {% url 'pybo:answer_create' question_id %} 같은 별칭을 사용했기 때문이다.

 

오류 해결을 위해 pybo/urls.py에 URL 매핑을 추가하자

 

파일 : C:\projects\mysite\pybo\urls.py

path('answer/create/<int:question_id>/', views.answer_create, name='answer_create'),

 

이제 http://localhost:8000/pybo/answer/create/2/ 와 같은 페이지 요청하면 views.answer_create 함수 호출된다.

 

 

3. 뷰 함수

 

매핑에 정의된 views.answer_create 함수를 작성할 차례다. pybo/views.py 파일에 코드를 추가하자

 

파일 : C:\projects\mysite\pybo\views.py

from django.shortcuts import render, get_object_or_404, redirect # redirect 추가
from djagno.utils import timezone # 이 줄 코드도 추가
from .models import Question

# 코드 추가

def answer_create(request, question_id):
    """
    pybo 답변등록
    """
    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)

 

먼저 answer_create 함수 코드를 작성하면서 빨간 줄이 뜨면, 필요한 패키지를 임포트해주면 된다.

 

answer_create 함수의 매개변수 question_id는 URL 매핑에 의해 그 값이 전달된다.

http://localhost:8000/pybo/answer/create/2/ 페이지를 요청하면 question_id에 2라는 값이 전달된다.

 

답변을 등록하면 텍스트 창에 입력한 내용은 answer_create의 매개변수에서 request로 읽을 수 있다.

request.POST.get('content')는 POST로 전송된 form 데이터 항목 중 content 값을 의미한다.

답변 생성 위해 question.answer_set.create를 사용하였으며, question.answer_set은 질문의 답변이다.

Question과 Answer 모델은 ForeignKey로 연결되어 있어 이처럼 사용할 수 있다.

 

답변 저장 방법 중 Answer 모델을 직접 사용하는 방법도 있다.

 

from .models import Question, Answer


def answer_create(request, question_id):
    """
    pybo 답변등록
    """
    question = get_object_or_404(Question, pk=question_id)
    answer = Answer(question=question, content=request.POST.get('content'), create_date=timezone.now())
    answer.save()
    return redirect('pybo:detail', question_id=question.id)

 

결과는 동일하다. answer 모델을 쓰고 answer.save() 로 저장해주는 게 특징이다.

 

4. 답변 저장

 

이제 질문 상세 화면을 띄우자.

 

 

의도한대로 나오는 것을 확인할 수 있다. 이제 답변을 적고 답변을 등록해보자.

아직은 답변을 저장하더라도 아무 변화가 없다. 등록된 답변을 표시하는 기능을 템플릿에 추가해야 한다.

 

 

5. 답변 조회

 

등록된 답변을 질문 상세 화면에 표시해보자. 그러려면 질문 상세 html을 수정해야 한다.

 

파일 : C:\projects\mysite\templates\pybo\question_detail.html

<h5>{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div>
    <ul>
        {% for answer in question.answer_set.all %}
            <li>{{ answer.content }}</li>
        {% endfor %}
    </ul>
</div>

 

div 태그와 from 태그 사이에 해당 코드를 추가하자

 

답변을 확인할 수 있는 영역이다. question.answer_set.count를 출력하면 답변의 총 개수가 나온다.

 

이제 출력해보자

 

 

잘 나오고 있다.

 


※ 본 내용은 django 공부 기록이며, 점프 투 장고를 참고하였습니다.

https://wikidocs.net/book/4223

 

점프 투 장고

**점프 투 장고 오프라인 책 출간 !! (2020.12)** * [책 구입 안내](https://wikidocs.net/105844)

wikidocs.net

 

'Django > Django 기초' 카테고리의 다른 글

[Django] 2 - 8. 부트스트랩  (0) 2021.11.29
[Django] 2 - 7. 스태틱  (0) 2021.11.29
[Django] 2 - 4. 조회와 템플릿  (0) 2021.11.25
[Django] 2 - 3. 장고 관리자  (0) 2021.11.24
[Django] 2 - 2. 모델  (0) 2021.11.24