멋쟁이사자처럼 | [대학 11기] 파이썬 Django 실습 강의리뷰 : 챕터 5

Jimin K·2023년 5월 22일
0

테킷스쿨에는 멋쟁이사자처럼 [대학11기] 파이썬 Django 실습 강의가 있습니다.
멋쟁이사자처럼 대학 동아리에 소속되어 활동을 시작하며, 이 강의를 수강할 수 있게 되었습니다.
이번에 리뷰하려는 것은 ✨챕터 5 : 백엔드의 필수: CRUD 개발하기 ✨ 입니다.


① 웹 개발의 필수: CRUD란?

create, read, update, delete의 약자로, 소프트웨어가 가지는 기본적인 데이터 처리 기능이다.
웹 서비스의 기반이 되는 개념이다.

추가, 조회, 수정, 삭제로 한글로 부른다. 상황에 따라 고려해야 할 점들이 각각 다르다

삭제는 soft/hard 두 가지가 있다. 삭제했다고 정리하고 실제 완전히 삭제하지 않는 것을 soft delete이라고 한다.

클라이언트는 입력을 주로 하며, 서버에게 요청한다.
서버는 검증 및 연상을 주로 하며, 데이터베이스에게 요청한다.
데이터베이스는 처리(crud)를 하고, 다시 서버에게 이를 전송한다.

서버가 없어도 클라이언트와 데이터베이스 만 있어도 작동은 되지만, 서버가 있어야 보안을 강화하는 효과 등이 있다.

데이터베이스로의 데이터 요청과 응답이 기본적인 crud의 흐름이다.

② Create로 데이터 생성하기 (1)

데이터의 특정 테이블의 생성을 create이라고 한다.

create의 흐름 :
폼 요청 -> 폼 응답 -> 데이터 생성 요청 -> 데이터베이스의 데이터 응답

사용자에게 입력받는 데이터
시스템에서 생성하는 데이터
두 가지로 구성되어있다.

인증권한; 로그인이 필요하거나 관리지만 생성할 수 있게 한다
데이터 유효성; 클라이언트가 입력한 데이터가 유효한지 검증한다. (나이, 전화번호, 숫자만 들어오도록 만든다 등)

③ Create로 데이터 생성하기 (2)

이전까지 작업하던 파일에 들어가서

페이지 소스를 확인하면, 새로고침을 했을 때 네트워크에 다양한 경로로 내용을 가져온다는 것을 확인할 수 있다.

여기에서 {% ~~ %} 내용을 입력하면, 하드코딩 없이도 변경된 url 주소를 불러올 수 있다.
예를 들어서,

{% url 'posts:post-create' %} 

을 입력하면, 설령 경로가 create가 아니더라도 이름이 post-create에 해당하는 내용으로 url이 연결된다.

만약 기존 파일에서, 내가 파일을 브라우져로 가져오면 이를 받아들이는 프로그램을 만들과자 한다면, views.py와 post_form.html 파일을 수정하면 된다.

// posts > views.py
def post_create_view(request):
    if request.method == "GET":
        return render(request, 'posts/post_form.html/')
    else:
        image = request.FILES.get('image')
        content = request.POST.get('content')
        print(image)
        print(content)
        Post.objects.create(
            image=image,
            content=content,
        )
		return redirect('index')

post_create_view 는 내가 앞에서 view로 선언을 해두었기 때문에 꼭 return 값이 있어야 한다.

만약 post_form.html 을 수정하고자 한다면,

// post_form.html

{% extends 'base.html' %}
    {% block title %} POST 입력 {% endblock %}
{% block content %}

    <h1>POST 입력 화면</h1>
    <form action="{% url 'posts:post-create' %}" method="POST" enctype="multipart/form-data"> {% csrf_token %}
        <div>
            <label for="id_image">이미지</label>
            <input type="file" name="image" accept="image/*" id="id_image">
        </div>
        <div>
            <label for="id_content">내용</label>
            <textarea name="content" id="id_content" cols="30" rows="10"></textarea>
        </div>
        <div>
            <input type="submit">

        </div>
    </form>


{% endblock %}

사진을 넣으면, admin에서 해당 변경 내용을 확인할 수 있다.

settings 에 아래 코드를 추가하고

// config > settings.py


MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'

config 와 동등한 위치에서 media 폴더를 생성한다.
이제 이미지를 업로드하면 여기에 저장될 것이다..

④ Read로 데이터 조회하기 (1)

장고 디버그 툴바를 여기에서 다운받아 사용할 수 있다.

https://django-debug-toolbar.readthedocs.io/en/latest/installation.html

화면 우측에 생긴 바를 통해서 sql 등을 확인할 수 있다.

조금 디테일을 살려서 문서를 수정해보자.

여러 포스트를 모아서 리스트 모양으로 보고 싶다면 post_list_view 함수를 수정해주어야 한다.

def index(request):
    post_list = Post.objects.all().order_by('-created_at')

만약 여러 포스트를 최신순으로 정렬하고 싶다면,

def index(request):
    post_list = Post.objects.all().order_by('-created_at')

뒤에 order_by를 추가해준다.

그리고 리스트를 조회할 때 댓글에 대해서 알고싶다면post_card.html 파일에서 수정하면 되는데,

이미지가 있을 때, 이를 보이게 하고싶다면 card__body 부분에 아래의 코드를 추가해주면 된다.

        <div>
            {% if post.image  %}
                <img class="card__image" src="{{ post.image.url }}" alt=""/>
            {% else %}
                <img class="card__image" src="http://via.placeholder.com/600x600" alt=""/>
            {% endif %}
                
        </div>

댓글에 대한 내용은 아래의 코드를 추가해주면 된다.

 <div>
                <p class="">댓글 {{ post.comment_set.all.count }}개 {% if not detail %}모두 보기{% endif %}</p>
                <ul class="card__comment-group">
                    {% if not detail %}
                        {% for comment in post.comment_set.all %}
                            <li><p><span class="card__user-name">{{ comment.writer }}</span>{{ comment.content }}</p>
                            </li>
                        {% empty %}
                            <li><p>댓글 없음</p></li>
                        {% endfor %}
                    {% else %}
                        {% for comment in post.comment_set.all|slice:":2" %}
                            <li><p><span class="card__user-name">{{ comment.writer }}</span>{{ comment.content }}</p>
                            </li>
                        {% empty %}
                            <li><p>댓글 없음</p></li>
                        {% endfor %}
                    {% endif %}
                </ul>
            </div>
            <span class="card__created-at">{{ post.created_at|date:"Y년 m월 d일" }}</span>

작성자를 나타내는지의 유무와, 댓글이 없을 경우에는 '댓글 없음'을 출력하고 있다면 그 내용을 불러와 출력한다. 또한 시간을 제외한 날짜만 출력하기 위해서 맨 마지막 태그를 추가했다!

⑤ Read로 데이터 조회하기 (2)

포스트에서 게시물 글의 '더보기'를 누르면 상세내용이 나오게 만들고 싶다면, 기존의 post_card.html 파일에서 아래 코드를 추가해준다.

<a href="/posts/{{post.id}}">더보기</a>

저 코드에 있는 post.id는 index.html 파일에서 for 문을 돌리면서 그 내부에 post_card.html 파일을 불러왔기 때문에 가능하다.

만약 더 편하게 url을 불러오고 싶다면 urls.py 에 가서, post_detail_view에 이름을 추가해주면 된다.

      path('<int:id>', post_detail_view, name='post-detail'),

그리고 post_card도 수정하면 된다.

{% if not detail %}
                  <a href="{%  url 'posts:post-detail' post.id %}">더보기</a>
              {% endif %}

⑥ Update로 데이터 수정하기 (1)

기존에 작성한 게시물의 글 혹은 사진을 수정하고 싶다면, view.py 파일과 post_form.html 파일을 수정하면 된다.

// views.py


def post_update_view(request, id):
  post = Post.objects.get(id=id)
  if request.method == 'GET':
      context = { 'post':post }
      return render(request, 'posts/post_form.html/', context)
  elif request.method == 'POST':
      pass

if 문을 통해서 더 구체적인 코드를 작성할 수 있다.

// post_form.html


    <div>
          <label for="id_image">이미지</label>
          {% if post.image %}
              <p>현재 : <a href="{{post.image.url }}">{{ post.image.name }}</a></p>
              <p>변경 : </p>
          {% else %}
          {% endif %}
          <input type="file" name="image" accept="image/*" id="id_image">
      </div>
      <div>
          <label for="id_content">내용</label>
          <textarea name="content" id="id_content" cols="30" rows="10">{% if post %} {{ post.content }} {% endif %}
          </textarea>
      </div>

⑦ Update로 데이터 수정하기 (2)

기존에 파일을 수정하면서 이미지를 바꿀 수 있는데, 이 과정에서 기존 파일은 삭제되고 새 파일이 저장되어야 한다.
이를 위해서 views.py 파일을 수정한다.

// posts >  views.py

def post_update_view(request, id):
  
  # post = Post.objects.get(id=id)
  post = get_object_or_404(Post, id=id)
  
  
  if request.method == 'GET':
      context = { 'post':post }
      return render(request, 'posts/post_form.html/', context)
  elif request.method == 'POST':
      new_image = request.FILES.get('image')
      content = request.POST.get('content')
      print(new_image)
      print(content)
      
      if new_image:
          post.image.delete()
          post.image = new_image
          
      post.content = content
      post.save()
      return redirect('posts:post-detail', post.id )

더 안전한 코드 유지를 위해서

post = Post.objects.get(id=id)

대신에

  post = get_object_or_404(Post, id=id)

이를 이용할 수 있다.

⑧ Delete로 데이터 삭제하기 (1)

delete에 두 가지 종류의 삭제가 있는데, 소프트가 아닌 하드 딜리트, 즉 완전 삭제로 파일을 삭제하기 위한 코드를 이번 8과 9에서 살펴보자.

먼저 쉬운 url 연결을 위해서 urls.py에서 post_delete_view에 이름을 붙여주자

  path('<int:id>/delete/', post_delete_view, name='post-delete'),     

그리고 views.py 에서도 수정을 더해주는데, 만약 포스트를 찾지 못하면 404 에러 화면을 띄우도록 하며, 포스트가 있다면 해당 html파일로 연결하는 if 문과 return 문을 작성한다.


def post_delete_view(request, id):
  post = get_object_or_404(Post, id=id)
  
  if request.method == 'GET':
      context = { 'post': post }
      return render(request, 'posts/post_confirm_delete.html', context)  
  
  return render(request, 'posts/post_confirm_delete.html/')

삭제하기 버튼은 일단 임의로 수정하기 버튼 옆에 만들어 준다.

// templates > post_card.html

  <!-- 수정하기 버튼  -->
      {% if request.user == post.writer  %}
      <a href="{% url 'posts:post-update' post.id %}"> 수정하기 </a>
      <a href="{% url 'posts:post-delete' post.id %}"> 삭제하기 </a>
      {% endif %}

가장 중요한 post_confirm_delete.html 파일은 아래와 같다.

// templates > posts > post_confirm_delete.html

{% extends 'base.html' %}
  {% block title %} POST 삭제 {% endblock %}
{% block content %}

  <h1>POST 삭제 화면</h1>

  <form action="" method="POST">
      {% csrf_token %}
      <p>한 번 삭제된 데이터는 복구가 불가능 합니다. </p>
      <p>그래도 삭제 하시겠습니까? ID : {{ post.id }} </p> <br/> <br/>

      <a href="{% url 'index' %}">돌아가기</a>
      <input type="submit" value="삭제하기">

  </form>
  <br/>
  {% include 'mixin/posts/post_card.html' with detail=True %}

{% endblock %}

실행하면 화면은 아래와 같이 나온다.

⑨ Delete로 데이터 삭제하기 (2)

위의 코드에 이어서, 정말로 삭제를 하도록 만들기 위해서는 views.py에 post.delete()코드를 작성하는 것이 핵심이다.

// posts > views.py

def post_delete_view(request, id):
  post = get_object_or_404(Post, id=id)
  
  if request.method == 'GET':
      context = { 'post': post }
      return render(request, 'posts/post_confirm_delete.html', context)  
  else:
      post.delete()
      return redirect('index')



더 다양한 강의노트 및 강좌 후기 👉🏻 https://blog.naver.com/jimin201396

profile
아둥바둥

0개의 댓글