해리의 데브로그

Django 09 - 1:N 관계 설정 / 댓글 기능 구현

|

Django 08 - Template 에서 하드코딩된 URL 을 제거하기

|

Django 07 - CRUD 4 (Delete, Update)

|

Django 06 - CRUD 3 (Read)

|

Django 05 - CRUD 2 (Create & Read)

|

Model을 활용한 CRUD 구현 (2)

Create (Create 페이지 구현)

#views.py
from django.shortcuts import render
from .models import Post

def new(request):
    return render(request, 'new.html')


def create(request):
    title = request.GET.get('title')
    content = request.GET.get('content')
    
    post = Post(title=title, content=content)
    post.save()
    
    return render(request, 'create.html')


#urls.py
from posts import views

urlpatterns = [
    path('create/', views.create),
    path('new/', views.new),
]
<-- new.html -->
<body>
    <form action="/posts/create/", method="get">
        <input type="text" name="title"/>
        <input type="text" name="content"/>
        <input type="submit" value="Submit"/>
    </form>

</body>
    
<-- create.html -->
<body>
   <h1> 성공적으로 Post를 생성 했습니다! </h1>
</body>
  • views.py 에서 render 함수로 new.html 을 호출함.
  • input 태그를 통해 들어오는 값은 총 2가지로, 각각 titlecontent라는 name의 속성으로 정의 되어 있다. 여기서 Dict의 구조를 띔. {title: 사용자 입력 값, content: 사용자 입력값}

  • views.pycreate 함수에서 Dict에서 저장된 value값을 가져와 각각 titlecontent 라는 변수에 저장.
title = request.GET.get('title')
content = request.GET.get('content')
  • 데이터베이스에 내용을 저장하는 코드를 작성함. 아래의 경우, Post 클래스를 사용하기 위해 models.py에 작성된 Post 클래스를 import를 해와야함.
from .models import Post

post = Post(title=title, content=content)
post.save()
  • 최종적으로, new.html 에서 사용자가 내용을 입력하면, form 태그 action 속성으로 연결된 create.html 으로 이동되어, views.py 에 정의된 create 함수가 실행된다.
  • 해당 함수에 정의된 변수명에 따라, 데이터베이스에 내용이 저장되며, 사용자는 create.html 에 따라, “성공적으로 Post되었습니다” 라는 결과를 화면을 보게 된다.

URL 구조 변경

지금까지 우리는 프로젝트 폴더 내에 존재하는 urls.py (어플리케이션 폴더의 상위디렉토리)에 모든 url을 저장해왔다. 그런데 만약, 한 프로젝트 내에 무수히 많은 어플리케이션을 생성하고, 관련 url을 urls.py에 작성한다면, traceability 적인 측면 뿐만 아니라 직관적으로 각 어플리케이션에 해당하는 url을 구분하기 힘들 것이다.

따라서, urls.py를 각 어플리케이션 내에 새로 생성하여, 손쉽게 urls.py를 관리 할 수 있도록 해보자.

  • 어플리케이션 내에 urls.py 작성
from django.urls import path
from . import views
#현재 디렉토리 내에 views.py를 불러오므로 from 에는 현재 디렉토리를 의미하는 . 을 써줌.

urlpatterns = [
    path('create/', views.create),
    path('new/', views.new),
]
#일반적인 작성방법대로, urlpatterns을 작성한다. 
  • 상위 디렉토리(프로젝트 폴더) 내 urls.py 수정
from django.urls import path, include

urlpatterns = [
    path('posts/', include('posts.urls')),
    path('admin/', admin.site.urls),
]

path의 첫 번째 인수로, 'posts/' 값을 줌에 따라, posts(어플리케이션)에 적용되는 모든 url을 직관적으로 이해할 수있음. 또한 두번째 인수로, include('posts.urls') 을 주어, posts(어플리케이션) 내 urls.py와 연결을 시켰음. 이 때, 외장 함수인 include를 import 하였음.

Read (1) - 리스트 페이지 구현

  • views.py
    • 모델 Post 내 DB에 저장된 모든 값을 불러오는 objects.all() 을 입력한 후, posts 변수에 저장
    • 해당 변수를 템플릿 변수로 index.html으로 함께 넘김
#views.py
def index(request):
    #데이터 베이스에 저장된 모든 값을 불러옴.
    posts = Post.objects.all()
    return render(request, 'index.html', {'posts':posts})

#urls.py
urlpatterns = [
    path('', views.index),
]
  • index.html
    • 템플릿 변수로 넘어간 posts 를 진자템플릿을 사옹하여 반복문을 돌림
    • 반복문 안에서, 객체의 멤버변수인 .title.content 를 진자템플릿을 불러옴.
<body>
    <h1>Post Index</h1>
    <ul>
    <-- 반복문을 돌리기 위해 jinja 템플릿 사용 -->
    
    </ul>
</body>

Read (2) - 디테일 페이지 구현

우리가 작성한 index.html 은 데이터베이스에 입력한 레코드 전체에 대한 정보를 보여줬음. 이제, 게시판 안의 글의 내용을 보는 것과 같이, 클릭하여 들어가서 세부 내용을 보여주는 페이지를 생성해보자.

레코드에 대한 세부 정보를 보여주기 위해서는, 각 레코드가 갖고 있는 고유값(id; pk)로 접근을 해야 함. 이를 위해 id값을 파라미터로 갖고오는 Variable routing을 설정 해야 함.

예) 기본주소/posts/1

  • views.py & urls.py
    • detail 함수의 두번째 파라미터인 post_id 는 레코드의 고유키를 의미하는 variable routing임. 이는 urls.pypath 함수의 첫번째 인자와 반드시 일치 시켜줘야함.
    • post = Post.objects.get(pk=post_id) : Post라는 모델 클래스를 통해 저장된 1번(pk=1) 레코드를 post 라는 변수로 저장함. 이때 postPost 클래스의 인스턴스라고 볼 수 있음.
    • ‘post’ 를 템플릿 변수로 지정하였으며, 사용자의 편의상, Dict의 key값와 value값을 post로 일치시켰음. 따라서, detail.html 에서 템플릿 변수 post 를 입력하면, Post의 인스턴스이자, 템플릿 변수의 key값인 post가 호출 됨.
#views.py
def detail(request, post_id):
    post = Post.objects.get(pk=post_id)
    return render(request, 'detail.html', {'post':post})

#urls.py
urlpatterns = [
    path('<int:post_id>/', views.detail),
]
  • detail.html
    • 위의 설명에 이어, Post의 인스턴스인 post 는 클래스에서 정의된 멤버 변수(예, post.title / post.content )를 불러올 수 있음.
    • 추가로, 레코드 전체에 대한 정보가 담겨 있는 기본주소/posts/ 또는 (index.html) 으로 돌아가기 버튼을 만들기 위해, a 태그를 사용 하였음.
<body>
    <h1>Post Detail</h1>
    <h2>Title : </h2>
    <p> Content : </p>
    <a href="/posts/">List</a>
 
</body>