CRUD는 소프트웨어가 기본적으로 갖는 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 의미한다. Django를 통해 간단한 게시판을 만들어보며 Django의 프로젝트 흐름을 파악하고 CRUD를 이해한다.
프로젝트 생성
①. CRUD라는 프로젝트를 생성한다.
$ django-admin startproject CRUD . |
②. 게시판을 만들 posts라는 애플리케이션을 생성한다.
$ python manage.py startapp posts |
③. 프로젝트 폴더의 settings.py에서(CRUD/settings.py) 생성된 애플리케이션을 등록한다.
Model 만들기
①. 애플리케이션 폴더의 models.py에서 Post라는 클래스를 정의하여 속성들의 데이터형을 생성한다.
게시판의 경우 간단하게 제목, 내용, 작성시간, 수정시간을 데이터베이스에 저장하도록 한다.
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=10) # 제목
content = models.TextField() # 내용
created_at = models.DateTimeField(auto_now_add=True) # 작성시간
updated_at = models.DateTimeField(auto_now=True) # 수정시간
def __str__(self):
return self.title
②. 설계한 클래스를 바탕으로 데이터베이스에 테이블의 형태로 저장될 수 있도록 설계도를 만들어준다.
$ python manage.py makemigrations |
③. 이후 실제로 테이블의 형태로 변환하여 데이터베이스에 저장되도록 migrate를 한다.
$ python manage.py migrate |
④. admin 페이지를 위해 관리자 계정을 생성한다.
$ python manage.py createsuperuser |
⑤. 애플리케이션 폴더의 admin.py에 Post 테이블을 등록한다.
from django.contrib import admin
from .models import Post
admin.site.register(Post)
URL 분리와 템플릿 상속
간단한 게시판을 만들 때는 큰 효과를 발휘하지 않겠지만 추후에 더욱더 복잡한 프로젝트를 위해서 애플리케이션 별로 URL을 분리하고 각각의 페이지가 공통된 UI를 갖도록 기본 템플릿을 만들어 상속을 해주도록 한다.
①. 프로젝트 폴더 하위에 templates라는 폴더를 만들어주고 그 안에 기본 베이스가 되는 HTML을 생성한다. (crud/templates/base.html)
②. settings.py에 가서 TEMPLATES라는 리스트 안의 딕셔너리 중 'DIRS'에 템플릿을 상속하여 사용할 수 있도록 설정한다. 설정 후에 애플리케이션의 HTML문서에서 상속하여 사용한다.
'DIRS': [BASE_DIR/'CRUD'/'templates'],
③. urls.py에서 include 모듈을 통해 애플리케이션 별로 URL을 분리한다.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', include('posts.urls')),
]
④. posts 애플리케이션 폴더에도 urls.py를 생성하여 URL로 요청을 받았을 때 View에서 처리하도록 한다. posts/에 들어오면 views.py에서 index함수가 처리한다.
from djang.urls import path
from . import views
app_name = "posts"
urlpatterns = [
path('', views.index, name="index")
]
READ
메인 페이지에 작성된 글의 목록을 출력한다.
①. views.py에서 index 함수를 생성하고 테이블에 저장된 모든 데이터를 불러와 변수로 저장하고 index.html에 넘겨준다.
from django.shortcuts import render
from .models import Post
# READ - 글의 목록을 보여주는 메인 페이지
def index(request):
posts = Post.objects.order_by('-pk')
context = {
'posts':posts,
}
return render(request, 'posts/index.html', context)
②. posts/templates/posts/index.html에서 View에서 넘겨받은 변수를 활용하여 글의 목록을 출력한다. for문을 활용하여 모든 글의 정보를 받아 각각의 자리에 위치하도록 하였다.
{% extends 'base.html' %}
{% block content %}
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">TITLE</th>
<th scope="col">CONTENT</th>
<th scope="col">작성 시간</th>
</tr>
</thead>
<tbody>
{% for post in posts %}
<tr>
<th scope="row">{{ post.pk }}</th>
<td>{{ post.title }}</td>
<td>{{ post.content }}</td>
<td>{{ post.updated_at }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
③. 여기까지 만들어진 메인 페이지는 다음과 같다.
CREATE
네비게이션 바에서 "새 글 작성"을 누르면 글을 작성하는 페이지로 이동하도록 한다.
①. urls.py에 create라는 경로를 추가한다.
from django.urls import path
from . import views
app_name = "posts"
urlpatterns = [
path('', views.index, name="index"),
path('create/', views.create, name="create"),
]
②. View에서 "새 글 작성"을 눌렀을 때 새 글을 작성하는 페이지로 이동하고 새 글을 작성했을 때는 데이터베이스에 저장하는 로직을 구성한다. "새 글 작성"은 <a>태그로 되어 있는데 이는 GET 요청을 한다.
def create(request):
if request.method == 'POST':
pass
else:
return render(request, 'articles/newpost.html')
③. 새 글을 작성하는 페이지인 newpost.html로 이동하여 form형태 안에서 글을 작성하도록 한다. 작성된 글은 POST로 다시 create에 보내지게 된다.
{% extends 'base.html' %}
{% block content %}
<form actions="{% url 'posts:create' %}" method="POST">
{% csrf_token %}
<h2>새 글 작성</h2>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">TITLE</label>
<input type="text" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="title">
</div>
<div class="form-floating mb-3">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea" name="content"></textarea>
<label for="floatingTextarea">CONTENT</label>
</div>
<button type="submit" class="btn btn-primary">완료</button>
</form>
{% endblock content %}
④. 이렇게 만들어진 새 글 작성 페이지는 다음과 같다.
⑤. 이제 views.py로 돌아가 create의 POST 동작을 구현한다. 작성된 글은 POST로 전송이되고 객체의 create() 메서드를 통해 데이터베이스에 저장하도록 한다. 완료가 되었다면 redirect()로 메인 페이지를 보여주도록 한다. redirect는 import해서 사용한다.
def create(request):
if request.method == 'POST':
Post.objects.create(title=request.POST.get('title'), content=request.POST.get('content'))
return redirect('posts:index')
else:
return render(request, 'posts/newpost.html')
이렇게 작성된 글은 메인 페이지의 글 목록에 추가된다.
상세 페이지 보기
글의 내용 클릭시 글의 세부 내용을 보여주는 화면으로 이동하는 것을 구현한다.
①. detail이라는 경로를 urls.py에 추가하며 URL에 해당 글의 pk값을 전달받도록 한다.
from django.urls import path
from . import views
app_name = "posts"
urlpatterns = [
path('', views.index, name="index"),
path('create/', views.create, name="create"),
path('detail/<int:pk>', views.detail, name="detail"),
]
②. View에서 해당 pk값에 해당하는 글을 보여주도록 구현하여 detail.html에 전달한다.
def detail(request, pk):
post = Post.objects.get(pk=pk)
context = {
'post':post,
}
return render(request, 'posts/detail.html', context)
③. detail.html에 상세 내용을 보여주는 템플릿을 작성한다.
{% extends 'base.html' %}
{% block content %}
<h2>TITLE: {{ post.title }}</h2>
<hr>
<p>{{ post.content }}</p>
<p class="text-sm">작성시간: {{post.created_at}}</p>
<p clas="text-sm">수정시간: {{post.updated_at}}</p>
<div class="d-flex">
<button type="button" class="btn btn-primary">수정</button>
<button type="button" class="btn btn-danger">삭제</button>
</div>
<a href="{% url 'posts:index'%}">BACK</a>
{% endblock content %}
④. 상세 내용 페이지는 다음과 같다.
UPDATE
상세 내용 페이지에서 수정을 누르면 글을 수정하는 페이지로 넘어가 글을 수정해보자.
①. update라는 경로를 추가해주고 pk값을 전달받아 해당 글을 수정할 수 있도록 한다.
from django.urls import path
from . import views
app_name = "posts"
urlpatterns = [
path('', views.index, name="index"),
path('create/', views.create, name="create"),
path('detail/<int:pk>', views.detail, name="detail"),
path('update/<int:pk>', views.update, name="update"),
]
②. View에서 글을 수정하는 페이지로 이동하는 GET 요청을 받았을 때 update.html로 이동하도록 한다.
def update(request, pk):
if request.method == 'POST':
pass
else:
post = Post.objects.get(pk=pk)
contenxt = {
'post':post,
}
return render(requst, 'posts/update.html', context
③. update.html에서는 newpost.html과 비슷하게 구성하여 수정하는 페이지를 구성한다. 이때 title의 value를 전달받은 변수의 title값으로 하고 textarea안에는 text.content를 추가하도록 한다.
{% extends 'base.html' %}
{% block content %}
<form method="POST">
{% csrf_token %}
<h2>수정하기</h2>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">TITLE</label>
<input type="text" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="title" value="{{post.title}}">
</div>
<div class="form-floating mb-3">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea" name="content">{{post.content}}</textarea>
<label for="floatingTextarea">CONTENT</label>
</div>
<button type="submit" class="btn btn-primary">수정</button>
</form>
{% endblock content %}
④. 이렇게 수정하는 페이지로 이동하면 다음과 같이 출력된다.
⑤. 수정하기 버튼을 눌렀을 때 views.py의 update함수에 전달되어 POST일 때 처리를 하도록 한다. 수정이 완료되었을 때 다시 메인 페이지로 돌아가도록 한다.
def update(request, pk):
if request.method == 'POST':
post = Post.objects.get(pk=pk)
post.title = request.POST.get('title')
post.content = request.POST.get('content')
post.save()
return redirect('posts:index')
else:
post = Post.objects.get(pk=pk)
context = {
'post':post,
}
return render(request, 'posts/update.html', context)
⑥. 실제 수정 후에 메인 페이지에 적용된 결과는 다음과 같다. 위에서 작성한 내용과 달라진 것을 확인할 수 있다.
DELETE
이제 상세 내용 페이지에 들어가서 글을 삭제 해보자
①. 삭제 버튼을 눌렀을 때 삭제를 하는 URL에 접근할 수 있도록 urls.py에 delete를 추가해준다. 이때에도 pk값을 넘겨주어 해당 글을 삭제하도록 한다.
from django.urls import path
from . import views
app_name = "posts"
urlpatterns = [
path('', views.index, name="index"),
path('create/', views.create, name="create"),
path('detail/<int:pk>', views.detail, name="detail"),
path('update/<int:pk>', views.update, name="update"),
path('delete/<int:pk>', views.delete, name="delete"),
]
②. View에서는 삭제한다는 GET 요청을 받아 처리를 한다. 수정과 삭제 버튼은 <a> 태그로 감쌌으며 <a> 태그는 GET 요청을 한다.
def delete(request, pk):
post = Post.objects.get(pk=pk)
post.delete()
return redirect('posts:index')
③. 글을 삭제 후에는 메인 페이지로 이동하며 삭제된 것을 확인할 수 있다.
이렇게 간단한 게시판을 만들어보면서 CRUD가 무엇인지 이해할 수 있었다. 또한 계속해서 게시판을 만들 때 버튼을 눌렀을 때 이동하지 않거나 오류가 많이 발생했는데 정리를 하면서 헷갈렸던 부분들을 확실히 알 수 있었다.
'WEB' 카테고리의 다른 글
[Django 09] Authentication (0) | 2021.03.23 |
---|---|
[Django 08] Forms (0) | 2021.03.16 |
[Django 06] Model (0) | 2021.03.10 |
[Django 05] form 사용하기 (0) | 2021.03.09 |
[Django 04] URL 분리하기 (0) | 2021.03.09 |