권태형 저자님의 '백엔드를 위한 DJANGO REST FRAMEWORK with 파이썬'을 기반으로 정리한 글입니다.
Chapter 1: 웹 기초
1. 웹 개발 기초 개념

백엔드
데이터베이스를 설계하고 설계된 데이터베이스를 바탕으로 데이터를 생성, 수정, 삭제, 조회 등의 기능을 구현하고 다룬다.
REST API
먼저 API에 대해 알아보자면, API란 Application Program Interface의 약자이다.
| API를 은행에 비유하자면, 은행은 돈을 관리하는 하나의 거대한 시스템이다. 우리는 그 시스템을 이용하는 고객(클라이언트)으로서, 은행의 자원인 돈을 사용하고 싶어한다. 이때 고객과 시스템을 연결해 주는 창구가 바로 은행원(API) 이다. 은행원은 고객이 은행의 돈이나 서비스에 접근할 수 있도록 도와주는 중간자(인터페이스) 역할을 한다. 덕분에 우리는 복잡하게 숨겨진 금고에 직접 접근하지 않아도 되고, 은행이 제공하는 다양한 금융 서비스를 간편하게 이용할 수 있다. |
다음으로 REST에 대해 알아보자면, REST란 Representational State Transfer의 약자이이다. 그리고 REST는 자원을 이름 등으로 구분해서 해당 자원에 대한 여러 정보를 주고 받는 것 자체를 의미한다.
즉, REST API란 자원을 이름으로 구분해서 표현해놓고, 그 자원들을 주고 받도록 만들어놓은 시스템의 창구라고 할 수 있다. 좀 더 쉽게 접근하자면, 응용 프로그램이 시스템에 있는 자원(데이터)을 쉽게 사용하기 위해 시스템이 각 자원에 이름을 붙여서 정리해놓은 것이라고도 이해할 수 있다.
이러한 REST API는 프론트엔드(응용프로그램)와 백엔드(시스템)가 데이터를 주고 받기 위한 대표적인 방법이다.
백엔드 시스템을 개발하면, 프론트엔드에서 만들어질 응용 프로그램이 백엔드 시스템의 데이터에 접근하고 싶어할 것이고,
그러한 요청에 대해 쉽게 데이터를 제공하도록 하는 기능(API)을 잘(REST하게) 만들어야 한다.
JSON
REST API는 프론트엔드에게 데이터를 제공하기 위한 백엔드 시스템에 있는 창구이다.
이때, 데이터를 특정 양식에 맞춰 주고받는데, 해당 양식이 바로 JSON(JavaScript Object Notation)이다.
다음은 JavaScript에서 JSON을 사용한 예시이다.
{
id: 'abc',
age: 3,
photo: 'image.png'
}
2. 데이터베이스와 쿼리
테이블의 키
키는 데이터들 간 중복되지 않는 고유한 값을 가지는 Column(attribute)이다.
쿼리
쿼리는 질의라는 뜻을 갖고 있는데, 말 그대로 데이터베이스에게 물어보는 문장을 뜻한다. (요청)
이러한 요청의 종류는 크게 조회, 생성, 수정, 삭제로 구분할 수 있는데, 이것이 바로 REST API의 4가지 요소인 CRUD이다.
Chapter 2: Django 기본 컨셉 익히기
1. Django 시작하기
프로젝트 시작하기
프로젝트 시작에 앞서, 먼저 가상 환경을 만들어 설정하고그 위에서 프로젝트를 진행해야 한다.
이때, 가상 환경을 만드는 이유는 프로젝트마다 필요한 패키지 버전이 다르기 때문이다.
우선 프로젝트 폴더를 원하는 위치에 생성하고, 해당 폴더를 VSCode로 열어본다.
그리고 VSCode의 Terminal에 다음과 같은 명령어를 입력한다.

가상 환경이 활성되었으니 아래 명령어를 통해 Django를 설치한다.

※ 위 버전은 현재 python과는 호환성 문제가 있기에 "pip install --upgrade django"를 통해 django를 업그레이드 한다.
이렇게, 설치를 모두 완료한 후, 아래 명령어를 통해 새로운 Django 프로젝트를 만든다.

이에 더하여, 아래 명령어를 통해 app을 추가한다.

이 상태에서 아래 명령어를 입력하여 프로젝트를 실행한 후, "http://127.0.0.1:8000" 주소에 접속한다.


이때 8000은 Django가 사용하는 포트 번호이다.
포트는 웹 서비스가 돌아가고 있는 컴퓨터로 다른 사람들이 들어오기 위한 문이다. 몇 가지 문들은 이미 누군가의 전용 출입구라서 Django는 8000번째 문을 사용한다고 이해할 수 있다.
※ Django 실행 멈추고 다시 터미널로 돌아오려면 터미널 화면에서 'Ctrl + C"를 입력하여 종료하, 면 된다.
2. Django 프로젝트 구조 살펴보기
Django 프로젝트와 앱
Project: 어떤 하나의 큰 서비스
- 만들고 있는게 웹 서비스라면 하나의 웹 사이트가 프로젝트임
App: Project 내 기능과 같은 요소들을 일정한 기준으로 나눠 놓은 단위
Example) 페이스북

- 회원 관련 내용
- 가입/로그인/친구 맺기 등 피드 관련 내용
- 글쓰기/삭제하기/수정하기/공유하기
- 메신저 관련 내용
- 채팅 보내기/채팅 받기/차단하기
Django 프로젝트 설정 마무리하기
myweb/settings.py를 열어 다음과 같이 일부 내용을 수정해 준다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'photo', #방금 만든 앱을 추가해 준다.
]
TIME_ZONE = 'Asia/Seoul' # 시간대를 한국으로 설정한다.
Django 프로젝트 구성요소 살펴보기
startproject와 startapp 명령어를 통해 각각 프로젝트와 프로젝트 내부에 들어갈 앱을 만들었는데,
이를 통해 최종적으로 만들어진 폴더 구조는 아래와 같다.

- manage.py: 따로 수정할 일은 없고, 그저 Django와 관련된 명령어를 처리해 주는 파일
- myweb: startproject로 만들어진 폴더로, Django 프로젝트의 설정 및 기본 기능을 위한 파일들이 존재
- myweb/settings.py: 프로젝트의 설정 파일로, 여러 옵션 설정 가능
- myweb/urls.py: 프로젝트의 url 주소를 등록해 놓는 파일
myweb/settings.py
DEBUG = True
해당 옵션은 디버깅 모드에 대한 옵션으로, True로 켜놓으면 만드는 웹 결과물에서 에러 발생 시, 그 에러에 대한 메시지가 웹 페이지에 그대로 노출되는 것을 의미한다.
개발할 때는 이를 보면서 에러를 고쳐나갈 수 있겠지만, 실제로 배포할 때는 사용자들 입장에서 이상하기도 하고, 해커들이 이를 본다면 프로젝트의 구조를 파악해 공격할 수도 있다. 따라서 배포할 때는 꺼놓고 배포해야 한다.
ALLOWED_HOSTS = []
허용할 호스트 주소에 대한 내용을 넣는 곳이다. 여기서 호스트 주소란 만든 Django 프로젝트가 돌아가는 환경의 접속할 수 있는 주소를 의미한다. 예를들어, 현재 로컬 환경에서 Django 프로젝트를 실행하면 http://127.0.0.1:8000에서 실행이 되는데, 여기서 127.0.0.1이 호스트 주소가 된다.
이후에 프로젝트를 배포할 때 배포하는 서버의 호스트 주소를 여기에 입력해야 외부에서 우리 프로젝트로 접속할 수 있게 된다.
※ 로컬 주소는 기본 값이라서 저 옵션 안에 선언해 주지 않아도 된다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'photo',
]
설치된 앱들을 등록하는 옵션이다. Django 프로젝트에서 사용할, 만든 앱들을 여기에 선언해 주어야 등록이 되어 프로젝트에서 정상적으로 적용이 된다.
Django 앱 구조로 알아보는 MTV 패턴

MTV 패턴은 Model, Template, View의 약자이다.
- Model: 앱의 데이터와 관련된 부분
- Template: 사용자에게 보이는 부분
- View: 그 사이에서 Model의 데이터를 Template으로 전달하고 Template에서 발생하는 이벤트를 처리하는 부분
3. Django Model 알아보기
어드민 페이지
Django에서 기본적으로 제공해 주는 관리자 페이지이다. 계정 등록을 위해서는 콘솔에 다음과 같은 명령어를 입력해야 한다.

모델이란
데이터베이스에 저장될 데이터의 모양을 정의하고 관련된 일부 기능을 설정해 주는 영역이다.
개체의 특징들을 뽑아서 이를 구성 요소(혹은 속성)로 하는 것을 모델링이라고 하고, 개체를 모델링한 결과물은 모델이 된다. 이렇게 만든 모델 형태의 데이터들을 데이터베이스에 쌓으면 데이터베이스 테이블이 된다.
즉, 모델을 데이터베이스에 적용시키면 그것은 테이블이 된다. 여기서 모델을 데이터베이스에 적용시키는 과정을 Migration(마이그레이션)이라고 한다.
Django 모델 만들기
python으로 개발하고 있으니 모델을 하나의 클래스로 만들 수 있다. 이 클래스는 models.py에서 작성할 것이고, 모델 클래스에서는 속성을 정의하고 각 속성에 대한 세부 설정을 진행한다.
photo/models.py에 들어가 아래와 같이 사진 모델 클래스를 만들 수 있다.
from django.db import models
class Photo(models.Model):
title = models.CharField(max_length=50)
author = models.CharField(max_length=50)
image = models.CharField(max_length=200)
description = models.TextField()
price = models.IntegerField()
위처럼 사진 모델을 Photo라는 클래스로 정의하였는데, 일반적인 클래스와 살짝 다른 점은 models.Model을 상속받았다는 점과 각 속성들을 models를 사용해 정의하였다는 점이다.
import를 하는 구문을 보면 django.db로부터 models를 가져오는데, models는 Django의 데이터베이스와 관련된 내용을 미리 작성해놓은 도구이다. 따라서 모델을 만들 때 models.Model이라는 클래스를 상속받아서 그 기능을 그대로 가져다 쓸 수 있다.
쓸만한 필드 종류
- CharField: 문자열(길이제한 필요)
- IntegerField: 정수
- TextField: 문자열(길이제한 필요 없음)
- DateField: 날짜
- DateTimeField: 날짜 + 시간
- FileField: 파일
- ImageField: 이미지 파일
- ForeignKey: 외래 키(관계)
- OneToOneField: 1대1 관계
- ManyToManyField: 다대다 관계
Django 모델 적용시키기
모델을 만들거나 수정하거나 삭제할 때, 즉 모델에 변화가 생겼을 때 마이그레이션이라고 하는 과정을 통해 프로젝트에 모델의 변경 사항을 적용시킨다.
- makemigrations: 모델을 변경한 내용을 기록하여 파일로 만들어주는 과정으로, app이름/migrations 폴더 내에 생기는 파일들이 바로 이 과정으로 만들어지는 파일임
- migrate: makemigrations에서 생성된 파일을 실제로 실행시켜 실제 데이터베이스에 변경 사항을 적용시켜주는 과정

즉, models.py에서 수정한 내용은 makemigrations와 migrate 과정을 거쳐 실제 db 파일까지 반영이 된다.
- 파이썬 코드의 수정이 실제 db 파일의 수정까지 이어짐
Django 모델 어드민 페이지 적용
photo/admin.py에 모델을 등록해 주면 된다.
from django.contrib import admin
from .models import Photo
# Register your models here.
admin.site.register(Photo)


4. Django Template 알아보기
Django에서 템플릿은 사용자에게 보이는 부분으로, 웹 페이지의 골격, 즉 HTML로 작성된 부분을 의미한다. (프론트 개발 영역)
Django Template의 특징
장고의 템플릿은 일반적인 HTML 작성과 99% 동일하다. 아주 작은 차이가 있는데, 이것은 Django만의 장점이라고 할 수 있는 Template Tag이다.
Template Tag는 HTML이 파이썬 코드로부터(즉, Django 프로젝트로부터) 데이터를 넘겨받아서 손쉽게 처리할 수 있는 도구이다. HTML로 웹 페이지를 만들면 HTML은 그저 마크업 언어이므로 정적인 웹 페이지를 보여주기만 한다. 무언가 데이터를 넘겨받아서 웹 페이지에 보여주기 위해서는 자바스크립트와 같은 도구가 도와주어야 하는데, Django에서는 아주 편하게도 파이썬으로부터 바로 데이터를 넘겨받을 수 있도록 하는 템플릿 태그가 있다.
템플릿 태그는 {}로 감싸는 형태로 새겼는데, 이 안에 데이터를 넣을 수도 있고 심지어 for나 if와 같은 파이썬의 기본적인 구문도 사용할 수 있어 쓰면 쓸수록 아주 편한 기능이라고 할 수 있다.
5. Django View, URL 알아보기
Django View란
장고의 뷰는 템플릿과 모델 사이를 이어주는 다리와 같은 역할을 한다. 아주 단편적인 역할만 보자면 뷰는 모델을 통해 데이터에 접근하여 템플릿으로부터 요청 받은 데이터를 뽑아와 템플릿에게 답변으로 보내준다.
프론트엔드가 백엔드에게 데이터를 요청했을 때 백엔드에서 데이터를 뽑아서 프론트엔드에게 제공해주는 과정을 뷰가 처리하고 이해하면 된다.
Django URL이란
URL은 Uniform Resource Locator의 약자로, 기능 개발의 마지막 단계로 프론트엔드가 백엔드에게 데이터를 요청하도록 도와준다. 라우팅 역할과 동시에 서버로 해당 주소에 할당된 리소스를 요청하는 역할을 한다. 여기서 리소스는 우리가 웹 브라우저로 보는 HTML 페이지 뿐만 아니라, 내부를 채우는 데이터 등을 포함하는 개념이다.
6. 사진 목록 화면 만들기
템플릿
템플릿은 화면마다 파일 하나씩 만들 것이기 때문에 폴더로 관리하는 것이 좋다. 또한, 앱마다 템플릿을 따로 정의할 것이기 때문에 photo 폴더 내에 templates라는 폴더(photo/templates)를 만들면 된다.
그리고 나중에 템플릿 파일을 불러올 때 'my_template.html'과 같은 이름으로 불러오게 되는데, 여러 앱을 만들다 보면 프로젝트를 구성할 때 이름이 같은 템플릿 파일들이 있을 수 있기 때문에 Django에서 충돌이 발생할 수도 있다.

따라서 이를 방지하기 위해 templates 폴더 내에 다시 앱 이름으로 폴더를 만들어서 'my_app/my_template.html'처럼 사용하도록한다. 현재 프로젝트에선 photo/templates/photo가 되도록 만들면 된다. 그 후, 해당 폴더 내에 템플릿 파일인 'photo_list.html'을 만들고 아래와 같이 코드를 작성하면 된다.
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1><a href"">사진 목록 페이지</a></h1>
<section>
<div>
<h2>
<a href=""">컴퓨터 웰시코기</a>"
</h2>
<img
src="https://wallpapercave.com/uwp/uwp4380686.jpeg" # 이미지 우클릭 후, 이미지 주소 복사
alt="컴퓨터 웰시코기"
width="300"
/>
<p>웰시코기, 1000원</p>
</div>
</section>
</body>
</html>
뷰
뷰는 데이터베이스에서 데이터를 꺼내 템플릿으로 전달하기도 하지만, 템플릿을 보이게 하는 역할도 수행한다.
photo/views.py
from django.shortcuts import render
def photo_list(request):
return render(request, 'photo/photo_list.html', {})
photo_list 함수를 만드는데, 해당 함수는 render를 사용해 photo/photo_list.html을 렌더링, 쉽게 말해 웹에 보여질 수 있도록 가공하여 전달한다. 이렇게 하면 photo_list()라는 함수가 불렸을 때 photo_list.html이 나타나게 된다.
URL
urls.py는 photo 앱 폴더가 아닌 myweb 프로젝트 폴더 안에 있다. 프로젝트 전체의 URL은 myweb/urls.py가 관리하고, 지금은 photo 앱에 대한 URL을 작성할 것이기 때문에 photo 폴더 안에 urls.py를 만들고, 다음과 같이 코드를 작성해 준다.
from django.urls import path
from . import views
urlpatterns = [ #urlpatterns는 "주소 -> 함수" 연결표
path('', views.photo_list, name='photo_list')
]
''라는 주소는 루트 주소, 즉 "https://127.0.0.1:8000"을 의미하게 되고, views.py를 불러와 photo_list 함수를 부르고 있다. 덕분에, photo_list 함수를 불렀으니 photo/photo_list.html 파일이 렌더링되어 웹 페이지에 잘 나오게 될 것이다.
그리고 마지막 단계로 프로젝트의 urls.py에 방금 만든 photo/urls.py를 아래의 코드를 통해 등록한다.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('photo.urls'))
]
이때 include는 다른 앱의 urls.py를 불러올 때 사용하는 함수이다.
이렇게 완료한 후 다시 runserver를 하고 127.0.0.1:8000으로 들어가면 아래와 같은 화면이 나온다.

하지만 현재 화면은 모델과 연결되어 있지 않아 실제 데이터를 가져오지 않는다.
템플릿
템플릿에서 뷰로부터 데이터를 받아오려면 템플릿 태그를 활용해야 한다. 템플릿 태그는 위에서 말했던 것처럼 {}를 사용하며 조건문, 반복문까지 HTML 위에 파이썬 문법처럼 활용할 수 있다.
실제 사진 목록 화면에서 가져올 데이터는 말 그대로 사진 목록이기 때문에, 사진 데이터를 여러 개 가져오게 될 것이다. 이를 고려해 여러 장의 사진을 반복문 속 태그로 간단히 표현해볼 수 있다.
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1><a href"">사진 목록 페이지</a></h1>
<section>
{% for photo in photos %}
<div>
<h2>
<a href="">{{pthoto.title}}}</a>
</h2>
<img src="{{photo.image}}" alt="{{photo.title}}" width="300" />
<p>{{photo.author}}, {{photo.price}}원</p>
</div>
{% endfor %}
</section>
</body>
</html>
뷰
뷰에서 마지막 인자에 있던 {}를 활용하면 템플릿으로 데이터를 보낼 수 있다. {} 안에 넣고자 하는 데이터를 데이터의 이름과 함께 보내주면 된다.
그전에, 모델에서 데이터를 꺼내와야 할텐데, 이는 Django에서 제공하는 ORM(Object Relational Mapping) 기능을 활용하여 쉽게 진행할 수 있다. Django는 ORM 기능을 통해 파이썬 문법으로 데이터베이스 쿼리를 실행하는 것과 동일한 효과를 갖도록 한다.
ORM이란?
데이터베이스의 테이블을 파이썬 객체처럼 다루게 해주는 기능이다.
즉, SQL 문을 직접 쓰지 않아도 파이썬 코드로 데이터베이스를 조작할 수 있게 해주는 기술이다.
Example
SQL에서 이렇게 쓰는 것을
SELECT * FROM photo WHERE author = 'arsenic';
Django ORM에서는 이렇게 사용할 수 있다.
Photo.objects.filter(author='arsenic')
from django.shortcuts import render
from .models import Photo
def photo_list(request):
photos = Photo.objects.all()
return render(request, 'photo/photo_list.html', {'photos': photos}) # '템플릿에서 접근할 이름': 뷰에서 가져온 값
Photo.objects.all()을 통해 Photo 모델 데이터를 모두 가져오고, 이를 {}에 넣어서 템플릿으로 전달하는 코드이다.
이제 다시 실행해 보면 관리자 페이지에서 등록한 사진들이 잘 나오는 것을 확인 할 수 있다.

7. 사진 게시물 보기 화면 만들기
템플릿
photo/templates./photo 안에 photo_detail.html 파일을 아래와 같이 만든다.
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1>{{photo.title}}</h1>
<section>
<div>
<img src="{{photo.image}}" alt="{{photo.title}}" width="300" />
<p>{{photo.description}}</p>
<p>{{photo.author}}, {{photo.price}}원</p>
</div>
</section>
</body>
</html>
뷰
views.py에 함수 추가
from django.shortcuts import render, get_object_or_404
from .models import Photo
def photo_list(request):
photos = Photo.objects.all()
return render(request, 'photo/photo_list.html', {'photos': photos})
def photo_detail(request, pk=pk):
photo = get_object_or_404(Photo, pk)
return render(request, 'photo/photo_detail.html', {'photo': photo})
get_object_or_404()는 모델로부터 데이터를 찾아보고 만약 찾는 데이터가 없다면 404 에러를 반환하는 함수이다. 이를 통해 찾는 데이터가 없는 경우에 대한 에러 처리를 Django가 알아서 할 수 있도록 한다. 위 코드에서는 pk, 즉 모델의 데이터들을 구분하는 Django의 기본 ID 값으로 데이터를 찾는다.
- primary key: 데이터를 유일하게 구분할 수 있음
그리고 이렇게 찾은 photo 데이터를 photo_detail.html에게 보낸다.
URL
photo/urls.py에 아래 코드 추가
from django.urls import path
from . import views
urlpatterns = [
path('', views.photo_list, name='photo_list'),
path('photo/<int:pk>', views.photo_detail, name='photo_detail'),
]
여기서 <int:pk> 부분은 pk라는 이름의 정수형 변수가 들어갈 자리라는 것을 의미한다.
그리고나서 메인 화면에서 세부 화면으로 이동할 수 있도록 photo_list.html에 이 URL에 대한 뷰를 설정한다.
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1><a href"">사진 목록 페이지</a></h1>
<section>
{% for photo in photos %}
<div>
<h2>
<a href="{% url 'photo_detail' pk=photo.pk %}">{{photo.title}}</a>
</h2>
<img src="{{photo.image}}" alt="{{photo.title}}" width="300" />
<p>{{photo.author}}, {{photo.price}}원</p>
</div>
{% endfor %}
</section>
</body>
</html>
※ {% . . . %}: 템플릿 태그를 감쌀 때 사용하는 문법으로 단순 변수 출력({{ . . . }})과 달리, 명령이나 로직 수행시 사용한다.

8. 사진 게시물 작성 기능 만들기
템플릿
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1><a href="/">홈으로 돌아가기</a></h1>
<section>
<div>
<h2>New Photo</h2>
<form method="POST">
{% csrf_token %} {{form.as_p}}
<button type="submit">완료!</button>
</form>
</div>
</section>
</body>
</html>
Form은 사용자가 데이터를 입력하여 서버로 보내도록 도와주는 양식이다. 사용자는 이 양식을 채워서 POST 방식으로 요청을 보내면 서버에서는 해당 요청을 받아 처리하게 된다.
- GET: URL에 데이터 붙어서 전송
- POST: 데이터 본문에 담아서 전송
form 태그 내부 문법
- csrf_token: 폼 전송 시 숨겨진 토큰을 자동으로 삽입해서, 서버가 정상적인 사이트에서 보낸 요청인지 확인 가능하도록 함
- form.as_p: Django에서 Form 객체를 HTML로 렌더링할 때 쓰는 문법으로, form을 <p> 태그로 만들어 준다는 의미
- form submit button: 버튼 클릭시, <form> 안 데이터가 method="POST" 방식으로 서버에 전송됨
※ Form 객체를 HTML로 렌더링하는 이유는, 서버에서 정의된 입력 규칙을 사용자에게 보여주고, 입력값을 입력받아 안전하게 처리하기 위해서이다.
폼
photo 앱 폴더 내에 forms.py 파일을 추가하여 다음과 같이 작성한다.
from django import forms
from .models import Photo
class PhotoForm(forms.ModelForm): # Django의 기본 ModelForm 상속받음
class Meta:
model = Photo
fields = (
'title',
'author',
'image',
'description',
'price'
)
ModelForm의 Meta는 반드시 내부 클래스로 작성해야 하며, 그냥 클래스 속성으로 적으면 Django가 폼 정보를 인식하지 못한다.
뷰
from django.shortcuts import render, get_object_or_404, redirect
from .models import Photo
from .forms import PhotoForm
def photo_post(request):
if request.method == "POST":
form = PhotoForm(request.POST)
if form.is_valid():
photo = form.save(commit=False) # false -> DB에 바로 저장하지 않고 객체만 생성
photo.save() # DB에 저장
return redirect('photo_detail', pk=photo.pk)
else:
form = PhotoForm() # 빈 폼으로 새롭게 해당 페이지로 들어온 사용자 맞이
return render(request, 'photo/photo_post.html', {'form': form}) # post 화면
redirect는 다른 페이지로 이동시켜주는 함수이다.
URL
photo/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.photo_list, name='photo_list'),
path('photo/<int:pk>', views.photo_detail, name='photo_detail'),
path('photo/new/', views.photo_post, name='photo_post'),
]
photo_list.html을 수정하여 새로운 사진 게시물을 작성하기 위한 링크를 메인 화면에 삽입
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1><a href"">사진 목록 페이지</a></h1>
<h3><a href="{% url 'photo_post' %}">New Photo</a></h3>
<section>
{% for photo in photos %}
<div>
<h2>
<a href="{% url 'photo_detail' pk=photo.pk %}">{{photo.title}}</a>
</h2>
<img src="{{photo.image}}" alt="{{photo.title}}" width="300" />
<p>{{photo.author}}, {{photo.price}}원</p>
</div>
{% endfor %}
</section>
</body>
</html>

9. 사진 게시물 수정 기능 만들기
게시물 수정 기능은 게시물 작성 기능과 상당 부분 겹친다. 빈 폼에 새로 입력받는 것이라면 작성, 기존 데이터가 폼에 있는 상태에서 입력하는 것은 수정이다.
템플릿
비워져있는 폼에 데이터만 채우면 수정 기능이 되기 때문에 템플릿은 별도로 작성할 필요 없이 작성 기능의 템플릿인 photo_post.html을 동일하게 사용한다.
뷰
def photo_edit(request, pk):
photo = get_object_or_404(Photo, pk=pk)
if request.method == "POST":
form = PhotoForm(request.POST, instance=photo)
if form.is_valid():
photo = form.save(commit=False)
photo.save()
return redirect('photo_detail', pk=photo.pk)
else:
form = PhotoForm(instance=photo)
return render(request, 'photo/photo_post.html', {'form': form})
URL
urlpatterns = [
path('', views.photo_list, name='photo_list'),
path('photo/<int:pk>', views.photo_detail, name='photo_detail'),
path('photo/new/', views.photo_post, name='photo_post'),
path('photo/<int:pk>/edit/', views.photo_edit, name='photo_edit'),
]
그리고나서, photo_detail.html을 열어 세부 화면에 수정 기능을 추가한다.
<html>
<head>
<title>Photo App</title>
</head>
<body>
<h1>{{photo.title}}</h1>
<h3><a href="{% url 'photo_edit' pk=photo.pk %}">Edit Photo</a></h3>
<section>
<div>
<img src="{{photo.image}}" alt="{{photo.title}}" width="300" />
<p>{{photo.description}}</p>
<p>{{photo.author}}, {{photo.price}}원</p>
</div>
</section>
</body>
</html>

'Web > Django' 카테고리의 다른 글
| ForeignKey와 OneToOneField (0) | 2025.11.19 |
|---|---|
| Django로 웹 개발하기: todo_list (0) | 2025.10.29 |