Django

Django ORM with view [Django]

경상도상남자 2024. 9. 24. 16:04

shell에서 데이터 CRUD를 해봤다면 이제 view함수를 통해서 데이터를 처리해보자!!

참고로 url은 앱별로 따로 관리하도록 설계했다. 헷갈리지 말자!!

# todo_list_projcet/urls.py
from django.contrib import admin
from django.urls import path, include

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

 

 

CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말이다. 

 

내가 정의한 Todo 모델

# todos/model.py
from django.db import models

# Create your models here.
class Todo(models.Model):
    work = models.CharField(max_length=100)
    content = models.TextField()
    is_completed = models.BooleanField()
    created_at = models.DateField(auto_now_add=True)

 

1. Read(읽기)

여러개의 데이터 조회

1.1 path 경로 작성

# todos/urls.py

from django.urls import path
from . import views

app_name = 'todos'

urlpatterns = [
    path('', views.index, name='index'),
]

 

1.2 views.py 작성

작성 과정

  1. 조회할 모델 임포트
  2. 테이블의 필요한 데이터 조회
  3. dictionary에 데이터 넣기
  4. return에 세 번째 인자로 전달
# todos/views.py

from django.shortcuts import render
from .models import Todo # 모델 임포트

# Create your views here.
def index(request):
    work=Todo.objects.all() # todo 테이블의 모든 데이터 조회
    context = {
        'works': work
    }
    return render(request, 'todos/index.html', context)

 

1.3 html 수정

딕셔너리에 key, value 형태로 값을 받아온다

데이터가 여러 개일 경우 for문을 통해 데이터를 쉽게 나열 할 수 있다!!

{% extends "base.html" %}

{% block content %}
  <h1>할 일 목록 관리 프로젝트 메인 페이지</h1>
  <p>이 곳에서 할 일 목록을 관리합니다.</p>
  <ul>
    {% if works %}
      {% for work in works  %}
        <li>
          <a href="{% url "todos:detail" work.pk %}">{{ work.work }}</a>
          <p>완료 여부: {{work.is_completed}}</p>
        </li>
      {% endfor %}
    {% else %}
      <li>아직 할 일이 없습니다.</li>
    {% endif %}
  </ul>
{% endblock content %}

index페이지

 

한 개의 데이터 조회

이제 detail 페이지를 만들어서 한개의 데이터를 조회하는 방법을 알아보자!!

li 태그의 링크를 누르면 아래와 같은 그 데이터의 상세 정보를 확인 할 수 있는 페이지로 넘어가게 할 거다

그렇게 하기 위해서  variable Routing 을 활용할 것이다.

  • Variable Routing : URL 일부에 변수를 포함시키는 것(변수는 view 함수의 인자로 전달 할 수 있다)

http://127.0.0.1:8000/todos/{전달할 값}

detail 페이지 결과 화면

 

1.1 path 경로 작성

path에 Vairible Routing 방식으로 경로를 작성해준다. 

# todos/urls.py

from django.urls import path
from . import views

app_name = 'todos'

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

 

1.2 views.py 작성

하나의 데이터 이므로 get()으로 테이블에 데이터를 조회 

pk를 인자로 넘겨 받아 pk 값이 동일한 데이터을 조회한다. 

def detail(request, pk):
    work=Todo.objects.get(pk=pk)
    context = {
        'work': work
    }
    return render(request, 'todos/detail.html', context)

 

1.3 html 수정

딕셔너리에 key, value 형태로 값을 받아온다

{% extends "base.html" %}

{% block content %}
  <h1>할 일 목록 상세 페이지</h1>
  <hr>
  <p>{{ work.pk }}번째 할 일</p>
  <p>할 일: {{ work.work }}</p>
  <p>내 용: {{ work.content }}</p>
  <p>일 자: {{ work.created_at }}</p>
  <p>완 료: {{ work.is_completed }}</p>

{% endblock content %}

 

이렇게 하면 간단하게 조회를 해볼 수 있다~~

 

 

2. Create(생성)

이제 데이터를 생성하는 기능을 추가해보자!!

 

http://127.0.0.1:8000/todos/create_todo/ 에서 값들을 넣고 제출을 클릭하면 todos/{pk}러 redirect해서 확인 할 수 있도록 구현 할 것이다.  

 

 

 

/todos/create_todo/

 

todos/1/

 

※  Create 로직을 구현하기 위해 필요한 view 함수의 개수는?

  1. 사용자 입력 데이터를 받을 페이지를 렌터링 하는 함수(new)
  2. 사용자가 입력한 요청 데이터를 받아 DB에 저장하는 함수(create)

2.1 path 경로 추가

# todos/urls.py

from django.urls import path
from . import views


app_name = 'todos'

urlpatterns = [
    path('', views.index, name='index'),
    path('create_todo/', views.create_todo, name='create_todo'), # 2. create
    path('<int:todo_pk>/', views.detail, name='detail'),
    path('new_todo/', views.new_todo, name='new_todo'),          # 1. new
]

 

2.2 views.py 작성

create_todo, new_todo 함수 작성

보통 서버에 데이터를 제출하여 리소스를 변경(생성, 수정, 삭제)하는 경우는 GET이 아닌 POST 방식을 사용한다.

def create_todo(request):
    return render(request, 'todos/create_todo.html')

def new_todo(request):
    # 입력받는 데이터 추출
    work=request.POST.get('work')
    content=request.POST.get('content')

    # 저장 
    new_work=Todo(work=work, content=content, is_completed=False)
    new_work.save()
    return redirect('todos:detail', new_work.pk) # 상세 페이지로 redirect

 

2.3 create_todo.html 생성

  • DTL의 CSRF Token태그를 사용해 사용자에게 토큰 값을 부여해 요청시 토큰 값도 함께 서버로 전송
  • Django 서버는 해당 요청이 DB에 데이터를 하나 생성하는 (DB에 영향을 주는) 요청에 대해 "Django가 직접 제공한 페이지에서 데이터를 작성하고 있는것인지" 확인하는 수단이 필요
  • 겉모습이 똑같은 위조 사이트나 정삭적이지 않은 요청에 대한 방어 수단
  • 요청데이터 + 인증토큰 = 게시글 작성

CSRF (Cross-Site-Request-Forgery)

  • "사이트간 요청 위조"
  • 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹 페이지를 보안에 취약하게 하거나 수정, 삭제 등의 작업을 하게 만드는 공격 방법

POST일 때만 Token을 확인하는 이유?

  • POST는 단순 조회를 위한 GET과 달리 특정 리소스에 변경(생성, 수정, 삭제)을 요구하는 의미와 기술적인 부분을 가지고 있기 때문
  • DB에 조작을 가하는 요청은 반드시 인증 수단이 필요
  • 데이터베이스에 대한 변경사항을 만드는 요청이기 때문에 토큰을 사용해 최소한의 신원 확인을 하는 것
{% extends "base.html" %}

{% block content %}
  <h1>이 곳에서 할 일을 생성합니다.</h1>

  <form action="{% url "todos:new_todo" %}" method="POST">
    {% csrf_token %} 
    <input type="text" name="work">
    <br>
    <textarea name="content" id=""></textarea>
    <input type="submit" value="제출">
  </form>
{% endblock content %}

 

 

3. Delete(삭제)

detail 페이지에서 삭제 버튼 클릭시 해당 데이터가 삭제되고 index페이지로 이동하도록 할 것이다.

 

2번 째 할 일이 삭제된 index페이지

 

2.1 path 경로 추가

삭제할 데이터에 대한 정보는 variable Routing 을 활용해 받아온다.

 path('<int:todo_pk>/delete' ,views.delete_todo, name='delete' )

2.2 views.py 작성

def delete_todo(request,todo_pk):
    work=Todo.objects.get(pk=todo_pk)
    work.delete()
    return redirect('todos:index')

2.3 detail.html에 삭제 버튼 추가

  <form action="{% url "todos:delete" todo.pk %}" method="POST">
    {% csrf_token %}
    <input type="submit" value="삭제">
  </form>

 

4. Update(수정)

update 역시 create와 마찬가지로 두개의 view 함수가 필요하다. 

※  Update 로직을 구현하기 위해 필요한 view 함수의 개수는?

  1. 사용자 입력 데이터를 받을 페이지를 렌터링 하는 함수(edit)
  2. 사용자가 입력한 요청 데이터를 받아 DB에 저장하는 함수(update)

4.1 path 경로 추가

   path('<int:todo_pk>/update_todo/',views.update_todo, name='update_todo'),
   path('<int:todo_pk>/edit_todo/',views.edit_todo, name='edit_todo'),

 

4.2 views.py 작성

def update_todo(request,todo_pk):
    todo = Todo.objects.get(pk=todo_pk)
    context={
        'todo':todo
    }
    return render(request, 'todos/update_todo.html', context)

def edit_todo(request,todo_pk):
    
    # 요청받은 데이터
    work=request.POST.get('work')
    content=request.POST.get('content')

    # 데이터 조회
    todo = Todo.objects.get(pk=todo_pk)

    # 수정
    todo.work=work
    todo.content=content
    todo.save()
    return redirect('todos:detail', todo.pk)

 

4.3 update_todo.html 만들기

 

{% extends "base.html" %}

{% block content %}
  <h1>이 곳에서 할 일을 수정합니다.</h1>

  <form action="{% url "todos:edit_todo" todo.pk %}" method="POST">
    {% csrf_token %}
    <label for="work">work : </label>
    <input type="text" name="work" id="work" value="{{todo.work}}"> <br>
    <label for="content">content : </label>
    <textarea name="content" id="work" cols="30" rows="10">{{todo.content}}</textarea>
    <input type="submit" value="제출">
  </form>
{% endblock content %}

 

 

text 박스 안에 수정 전에 내용을 넣어줘서 어떤 내용인지 알기 쉽도록 한다.

수정 페이지

제출 클릭시 edit_todo 함수가 실행되면서 수정되고 detail 페이지가 redirect 된다.

detail 페이지

 

지금까지 기본적인 CRUD 기능을 구현해봤습니다~~

'Django' 카테고리의 다른 글

Static [Django]  (3) 2024.09.26
Django Form [Django]  (0) 2024.09.25
Django ORM [Django]  (3) 2024.09.23
Django Model 생성하기[Django]  (0) 2024.09.23
Django 프로젝트 생성하기 [Django]  (1) 2024.09.18