Flask

Chapter 4-3 실습_블로그 구현 (Flask-MySQL를 활용) templates/posts.html

Chansman 2025. 4. 22. 14:09

실습_블로그 구현 (Flask-MySQL를 활용)

이번 실습에서는 Flask와 MySQL을 활용하여 간단한 블로그 시스템을 구현합니다. 블로그 시스템은 사용자에게 게시물을 생성, 조회, 수정 및 삭제할 수 있는 기능을 제공합니다. 아래에서는 전체 코드를 제시한 후, 각 프로세스를 단계별로 설명하겠습니다.

프로젝트 구조

my_flask_app/
│
├── app.py                # Flask 애플리케이션 설정 및 라우팅
├── posts_routes.py       # 게시물 관련 라우트 처리
├── db.yaml               # 데이터베이스 연결 정보
└── templates/
    ├── posts.html        # 게시물 리스트 및 작성 폼
    └── post.html         # 개별 게시물 표시

 

블로그 구현 코드 설명

이번 블로그 구현 코드에서는 사용자가 게시물을 생성, 수정, 삭제할 수 있도록 하는 기능을 구현합니다. 코드에는 HTML, JavaScript, 그리고 Axios를 활용한 비동기 HTTP 요청 처리가 포함되어 있습니다. 아래는 각 프로세스에 대한 상세한 설명입니다.

전체 코드

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Blog Posts</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  </head>
  <body>
    <h1>Blog Posts</h1>

    <h2>Create a New Post</h2>
    <form id="postForm">
      <input type="hidden" id="postId" value="" />
      Title: <input type="text" id="title" /><br />
      Content:<br />
      <textarea id="content"></textarea><br />
      <input type="submit" value="Create Post" id="createButton" />
      <input
        type="button"
        value="Update Post"
        id="updateButton"
        onclick="submitUpdateForm()"
        style="display: none"
      />
    </form>

    <hr />

    <h2>All Posts</h2>
    <ul id="postsList"></ul>

    <script>
      let currentEditingId = null;

      document
        .getElementById("postForm")
        .addEventListener("submit", function (e) {
          e.preventDefault();
          const title = document.getElementById("title").value;
          const content = document.getElementById("content").value;
          if (currentEditingId === null) {
            createNewPost(title, content);
          } else {
            updatePost(currentEditingId, title, content);
          }
        });

      function createNewPost(title, content) {
        axios
          .post("/posts", { title, content })
          .then(function (response) {
            console.log(response);
            loadPosts();
            resetForm();
          })
          .catch(function (error) {
            console.error(error);
          });
      }

      function updatePost(id, title, content) {
        axios
          .put("/posts/" + id, { title, content })
          .then(function (response) {
            console.log(response);
            loadPosts();
            resetForm();
          })
          .catch(function (error) {
            console.error(error);
          });
      }

      function loadPosts() {
        axios
          .get("/posts")
          .then(function (response) {
            const posts = response.data;
            const postsList = document.getElementById("postsList");
            postsList.innerHTML = "";
            posts.reverse().forEach((post) => {
              const listItem = document.createElement("li");
              listItem.innerHTML = `
                            <h3>ID: ${post.id}</h3>
                            <h3>TITLE: ${post.title}</h3>
                            <p>CONTENT: ${post.content}</p>
                            <button onclick="deletePost(${post.id})">Delete</button>
                            <button onclick="loadPostForEditing(${post.id})">Edit</button>
                        `;
              postsList.appendChild(listItem);
            });
          })
          .catch(function (error) {
            console.error(error);
          });
      }

      function loadPostForEditing(id) {
        axios
          .get("/posts/" + id)
          .then(function (response) {
            const post = response.data;

            console.log("post", post);
            currentEditingId = post.id;
            document.getElementById("title").value = post.title;
            document.getElementById("content").value = post.content;
            document.getElementById("createButton").style.display = "none";
            document.getElementById("updateButton").style.display = "inline";
          })
          .catch(function (error) {
            console.error(error);
          });
      }

      function resetForm() {
        currentEditingId = null;
        document.getElementById("title").value = "";
        document.getElementById("content").value = "";
        document.getElementById("createButton").style.display = "inline";
        document.getElementById("updateButton").style.display = "none";
      }

      function submitUpdateForm() {
        const title = document.getElementById("title").value;
        const content = document.getElementById("content").value;
        console.log("currentEditingId", currentEditingId);
        if (currentEditingId) {
          updatePost(currentEditingId, title, content);
        } else {
          console.error("No post is currently being edited.");
        }
      }

      function deletePost(id) {
        if (confirm("Are you sure you want to delete this post?")) {
          axios
            .delete("/posts/" + id)
            .then(function (response) {
              console.log(response);
              loadPosts();
            })
            .catch(function (error) {
              console.error(error);
            });
        }
      }

      loadPosts();
    </script>
  </body>
</html>

각 프로세스의 흐름 설명

1. HTML Form 설정

  • 목표: 사용자가 새로운 블로그 게시물을 만들거나 기존 게시물을 수정할 수 있는 폼을 제공합니다.
  • 코드:
    • #postForm: 새로운 게시물을 작성하거나 수정하는 폼입니다.
    • Create Post 버튼과 Update Post 버튼이 있으며, 두 버튼은 서로 다르게 표시됩니다.
    • Update Post 버튼은 게시물이 수정 중일 때만 표시됩니다.
<form id="postForm">
  <input type="hidden" id="postId" value="" />
  Title: <input type="text" id="title" /><br />
  Content:<br />
  <textarea id="content"></textarea><br />
  <input type="submit" value="Create Post" id="createButton" />
  <input type="button" value="Update Post" id="updateButton" onclick="submitUpdateForm()" style="display: none" />
</form>

2. 게시물 생성 및 수정

  • 목표: 사용자가 새 게시물을 생성하거나 기존 게시물을 수정할 수 있습니다.
  • 코드:
    • submit 이벤트가 발생하면 폼 데이터를 확인하고, currentEditingId가 없으면 새로운 게시물을 생성하고, 있으면 기존 게시물을 수정합니다.
document.getElementById("postForm").addEventListener("submit", function (e) {
  e.preventDefault();
  const title = document.getElementById("title").value;
  const content = document.getElementById("content").value;
  if (currentEditingId === null) {
    createNewPost(title, content);
  } else {
    updatePost(currentEditingId, title, content);
  }
});

3. 게시물 생성 (createNewPost)

  • 목표: 새로운 게시물을 서버에 생성합니다.
  • 코드:
    • POST /posts API를 호출하여 새 게시물을 생성합니다.
    • 성공 시, loadPosts()를 호출하여 게시물 목록을 갱신하고, 폼을 초기화합니다.
function createNewPost(title, content) {
  axios.post("/posts", { title, content })
    .then(function (response) {
      loadPosts();
      resetForm();
    })
    .catch(function (error) {
      console.error(error);
    });
}

4. 게시물 수정 (updatePost)

  • 목표: 기존 게시물을 수정합니다.
  • 코드:
    • PUT /posts/{id} API를 호출하여 특정 게시물을 수정합니다.
    • 수정 후, loadPosts()로 갱신된 게시물 목록을 보여주고, 폼을 초기화합니다.
function updatePost(id, title, content) {
  axios.put("/posts/" + id, { title, content })
    .then(function (response) {
      loadPosts();
      resetForm();
    })
    .catch(function (error) {
      console.error(error);
    });
}

5. 게시물 목록 불러오기 (loadPosts)

  • 목표: 서버에서 모든 게시물을 조회하여 화면에 표시합니다.
  • 코드:
    • GET /posts를 호출하여 서버에서 게시물 목록을 불러옵니다.
    • 불러온 데이터를 화면에 표시하고, 각 게시물에 대한 삭제수정 버튼을 생성합니다.
function loadPosts() {
  axios.get("/posts")
    .then(function (response) {
      const posts = response.data;
      const postsList = document.getElementById("postsList");
      postsList.innerHTML = "";
      posts.reverse().forEach((post) => {
        const listItem = document.createElement("li");
        listItem.innerHTML = `
          <h3>ID: ${post.id}</h3>
          <h3>TITLE: ${post.title}</h3>
          <p>CONTENT: ${post.content}</p>
          <button onclick="deletePost(${post.id})">Delete</button>
          <button onclick="loadPostForEditing(${post.id})">Edit</button>
        `;
        postsList.appendChild(listItem);
      });
    })
    .catch(function (error) {
      console.error(error);
    });
}

6. 게시물 수정 폼 로드 (loadPostForEditing)

  • 목표: 게시물을 수정할 때 해당 게시물의 정보를 폼에 로드합니다.
  • 코드:
    • GET /posts/{id}를 호출하여 특정 게시물을 불러오고, 이를 폼에 채워줍니다.
    • Update Post 버튼을 표시하고 Create Post 버튼은 숨깁니다.
function loadPostForEditing(id) {
  axios.get("/posts/" + id)
    .then(function (response) {
      const post = response.data;
      currentEditingId = post.id;
      document.getElementById("title").value = post.title;
      document.getElementById("content").value = post.content;
      document.getElementById("createButton").style.display = "none";
      document.getElementById("updateButton").style.display = "inline";
    })
    .catch(function (error) {
      console.error(error);
    });
}

7. 게시물 삭제 (deletePost)

  • 목표: 사용자가 게시물을 삭제할 수 있도록 합니다.
  • 코드
    • DELETE /posts/{id}를 호출하여 서버에서 해당 게시물을 삭제합니다.
    • 삭제 후, 게시물 목록을 갱신합니다.
function deletePost(id) {
  if (confirm("Are you sure you want to delete this post?")) {
    axios.delete("/posts/" + id)
      .then(function (response) {
        loadPosts();
      })
      .catch(function (error) {
        console.error(error);
      });
  }
}

8. 폼 리셋 (resetForm)

  • 목표: 게시물 작성 폼을 초기화합니다.
  • 코드:
    • 폼 필드를 초기화하고, Create Post 버튼을 다시 표시합니다.
function resetForm() {
  currentEditingId = null;
  document.getElementById("title").value = "";
  document.getElementById("content").value = "";
  document.getElementById("createButton").style.display = "inline";
  document.getElementById("updateButton").style.display = "none";
}

마무리

이 코드는 HTML, JavaScript, Axios를 활용하여 간단한 CRUD 기능을 갖춘 블로그를 구현합니다. 사용자는 게시물을 추가, 수정, 삭제할 수 있으며, 서버에서 데이터를 불러와 동적으로 처리합니다.