Python/Python 웹프로그래밍

[Flask-⑤] 파이썬과 Flask로 만드는 게시판 CRUD 완벽 가이드

코딩 코디네이터 2025. 4. 15. 16:00
반응형

파이썬과 Flask로 만드는 게시판 CRUD 완벽 가이드 💻🛠️

게시글을 웹에서 직접 작성하고 수정하고 삭제까지?
Flask와 SQLAlchemy만 있으면 가능합니다!
이 글 하나면 게시판 CRUD 구현은 완전 정복할 수 있어요.

 

 

안녕하세요, 여러분 😊

오늘은 Flask 웹 애플리케이션에서 가장 많이 사용되는 기능 중 하나인 CRUD(Create, Read, Update, Delete)를 직접 구현해볼 거예요.

단순히 이론 설명에서 그치는 게 아니라, 실제 웹 브라우저에서 게시글을 작성하고 목록을 보고, 수정하거나 삭제하는 완전한 게시판 시스템을 만들 거예요.

이 과정을 통해 Flask와 ORM(SQLAlchemy)의 활용 방법을 보다 실제적인 방식으로 배워보게 될 거예요.

기초부터 차근차근, 코드 한 줄 한 줄 이해하며 따라올 수 있게 구성했으니, 초보자도 걱정 말고 끝까지 함께 해봐요! 😉

 

1. 게시글 작성 기능 구현 (Create 기능) 📝

웹 게시판에서 가장 먼저 구현할 기능은 게시글 작성입니다.

사용자가 직접 제목과 내용을 입력하고 저장 버튼을 누르면, 해당 내용이 데이터베이스에 저장되고 목록이나 상세 페이지로 이동하게 만들 거예요.

우선 기본적인 흐름을 코드와 함께 살펴볼게요.

① 글 작성 폼 구현

`/board/new` 경로로 GET 요청 시 사용자에게 제목과 내용 입력란을 보여주는 HTML 폼을 렌더링합니다.

아래는 템플릿 예시입니다:

<form method="POST">
  <label>제목</label><br>
  <input type="text" name="title"><br>
  <label>내용</label><br>
  <textarea name="content"></textarea><br>
  <button type="submit">작성하기</button>
</form>

 

CSRF 방지와 보안은 이후 단계에서 `Flask-WTF` 같은 라이브러리를 통해 보완할 예정입니다.

지금은 기본적인 기능 흐름을 먼저 구현해보는 데 집중할게요!

② POST 요청 처리 및 DB 저장

사용자가 작성한 제목과 내용을 받아 `Post` 모델을 통해 DB에 저장합니다.

아래는 Flask 라우트 코드 예시예요:

@app.route('/board/new', methods=['GET', 'POST'])
def create_post():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title or not content:
            flash('제목과 내용을 모두 입력해주세요.')
            return redirect(url_for('create_post'))

        post = Post(title=title, content=content)
        db.session.add(post)
        db.session.commit()

        flash('게시글이 작성되었습니다.')
        return redirect(url_for('post_detail', post_id=post.id))

    return render_template('create_post.html')

③ 피드백과 리다이렉트

작성 후에는 목록 페이지 또는 상세 페이지로 이동하며 flash를 통해 사용자에게 피드백 메시지를 전달할 수 있습니다.

템플릿에서 아래와 같이 메시지를 출력할 수 있어요:

{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}

🧪 실습 포인트

  • 제목 또는 내용을 비워서 제출했을 때 적절히 에러 처리가 되는지 확인해보세요.
  • 글 작성 후 DB에 제대로 저장되었는지 SQLAlchemy로 직접 쿼리하거나 목록 페이지에서 확인해보세요.
  • 작성 후 이동된 페이지에서 flash 메시지가 출력되는지 확인해보세요.

여기까지 구현하면 웹을 통해 실제로 글을 작성하고, 그것이 DB에 저장되는 전체 흐름을 직접 체험해볼 수 있어요.

다음은 작성된 글들을 조회해보는 기능, 목록 페이지로 넘어가볼게요!

 

 

2. 게시글 목록 조회 페이지 구현 (Read - 목록) 📋

게시판의 중심이 되는 페이지는 바로 목록 페이지입니다.

작성된 게시글들을 사용자에게 보여주는 역할을 하며, 각 게시글의 제목을 클릭하면 상세 페이지로 이동할 수 있어야 해요.

오늘은 이 목록 페이지를 Flask와 SQLAlchemy로 어떻게 구성할 수 있는지 하나씩 살펴보겠습니다.

① 목록 라우트 구현

/board 경로에서 모든 게시글을 조회할 수 있도록 라우트를 구현합니다.

작성일자를 기준으로 내림차순 정렬해 가장 최신 글이 위로 오도록 할 거예요.

@app.route('/board')
def post_list():
    posts = Post.query.order_by(Post.created_at.desc()).all()
    return render_template('post_list.html', posts=posts)

② 템플릿에서 게시글 목록 출력

게시글 데이터를 HTML에서 반복문을 통해 출력합니다.

게시글 제목을 클릭하면 상세 페이지로 이동하도록 링크를 걸어주세요.

<h2>게시글 목록</h2>
<ul>
  {% for post in posts %}
    <li>
      <a href="{{ url_for('post_detail', post_id=post.id) }}">{{ post.title }}</a>
      ({{ post.created_at.strftime('%Y-%m-%d %H:%M') }})
    </li>
  {% else %}
    <li>작성된 게시글이 없습니다.</li>
  {% endfor %}
</ul>

 

작성일이 보이도록 strftime을 활용해 날짜 포맷을 지정하는 것도 사용자 편의에 도움이 돼요.

③ (선택) 페이지네이션 기능 소개

글이 많아졌을 경우 모든 글을 한 페이지에 보여주는 것은 비효율적이에요.

이럴 땐 페이지네이션을 도입할 수 있습니다.

Flask-SQLAlchemy에서는 아래와 같이 페이지당 몇 개의 게시글을 보여줄지 설정할 수 있어요:

@app.route('/board')
def post_list():
    page = request.args.get('page', 1, type=int)
    posts = Post.query.order_by(Post.created_at.desc()).paginate(page=page, per_page=10)
    return render_template('post_list.html', posts=posts.items, pagination=posts)

 

실습에서는 구현하지 않아도 되지만, 프로젝트가 커질 경우 꼭 필요한 기능이에요.

Flask-Paginate 확장도 한 번 찾아보세요!

🧪 실습 포인트

  • 게시글 여러 개를 작성한 뒤, 최신 순으로 잘 정렬되는지 확인해보세요.
  • 게시글 제목을 클릭했을 때 해당 글의 상세 페이지로 잘 이동되는지 확인해보세요.
  • 아무 글도 없을 때 ‘게시글이 없습니다’ 문구가 표시되는지도 테스트해보세요.

이제 목록 페이지도 완성되었네요!

다음은 하나의 게시글을 눌렀을 때 나오는 상세 보기와 수정 기능을 구현해볼 차례입니다. 💪

 

 

3. 게시글 상세 보기 및 수정 기능 구현 (Read/Update) ✏️

게시글 목록에서 사용자가 특정 게시글을 클릭했을 때, 그 게시글의 내용을 보여주는 상세 보기 페이지와, 이후 수정할 수 있는 기능까지 구현해볼 거예요.

이 단계에서는 동적 라우팅, 데이터 조회, 그리고 POST 기반 수정 처리를 중심으로 배워보겠습니다.

① 게시글 상세 보기 페이지 구현

사용자가 게시글 제목을 클릭하면 /board/<post_id> 경로로 이동하도록 구현합니다.

이때 post_id를 기준으로 해당 게시글을 데이터베이스에서 조회해 보여줍니다.

@app.route('/board/<int:post_id>')
def post_detail(post_id):
    post = Post.query.get_or_404(post_id)
    return render_template('post_detail.html', post=post)

 

get_or_404()는 ID에 해당하는 데이터가 없을 경우 자동으로 404 에러를 반환해주기 때문에 안전한 처리 방식입니다.

② 수정 폼 페이지 구현

게시글 상세 페이지에서 ‘수정’ 버튼을 누르면 /board/<post_id>/edit 경로로 이동합니다.

이 경로에서는 기존 게시글 데이터를 폼의 초기값으로 미리 넣어 보여줍니다.

@app.route('/board/<int:post_id>/edit', methods=['GET', 'POST'])
def edit_post(post_id):
    post = Post.query.get_or_404(post_id)
    if request.method == 'POST':
        post.title = request.form['title']
        post.content = request.form['content']

        if not post.title or not post.content:
            flash('빈 칸 없이 입력해주세요.')
            return redirect(url_for('edit_post', post_id=post.id))

        db.session.commit()
        flash('게시글이 수정되었습니다.')
        return redirect(url_for('post_detail', post_id=post.id))

    return render_template('edit_post.html', post=post)

 

POST 요청 시 사용자가 입력한 값으로 기존 객체의 속성을 업데이트하고, db.session.commit()으로 저장합니다.

③ 수정 폼 템플릿 예시

<form method="POST">
  <label>제목</label><br>
  <input type="text" name="title" value="{{ post.title }}"><br>
  <label>내용</label><br>
  <textarea name="content">{{ post.content }}</textarea><br>
  <button type="submit">수정하기</button>
</form>

🧪 실습 포인트

  • 존재하지 않는 게시글 ID로 상세 페이지나 수정 페이지에 접근했을 때 404 오류가 잘 출력되는지 확인해보세요.
  • 수정 후 변경 사항이 목록 페이지나 상세 페이지에 즉시 반영되는지 확인해보세요.
  • 빈 입력값에 대한 처리와 사용자 피드백 메시지가 적절히 작동하는지 체크해보세요.

게시글 수정까지 완료했으니, 이제 남은 마지막 핵심 기능은 삭제입니다!

다음 단계에서는 게시글 삭제 처리 및 후속 처리까지 깔끔하게 구현해볼게요.

 

 

4. 게시글 삭제 기능 구현 (Delete) 🗑️

이제 게시글을 삭제하는 기능을 구현해볼 차례예요.

사용자 인터페이스에서 삭제 버튼을 클릭하면 해당 게시글이 실제로 데이터베이스에서 제거되고, 목록 페이지로 되돌아가게 만들 거예요.

삭제 전 확인 메시지를 띄우는 방법도 함께 알아봅시다.

① 삭제 버튼 추가하기

게시글 상세 페이지나 수정 페이지에서 삭제 버튼을 추가해 사용자가 클릭할 수 있도록 합니다.

아래는 HTML 폼을 사용한 간단한 예시예요:

<form method="POST" action="{{ url_for('delete_post', post_id=post.id) }}" 
      onsubmit="return confirm('정말 삭제하시겠습니까?');">
  <button type="submit">삭제하기</button>
</form>

 

자바스크립트의 confirm() 함수로 간단한 삭제 확인창도 띄워줍니다.

이렇게 하면 실수로 삭제하는 것을 방지할 수 있어요.

② Flask 라우트에서 삭제 처리

삭제 처리는 POST 방식으로 요청을 받아 처리하는 것이 일반적입니다.

아래는 Flask에서 삭제를 처리하는 라우트 예시입니다.

@app.route('/board/<int:post_id>/delete', methods=['POST'])
def delete_post(post_id):
    post = Post.query.get_or_404(post_id)
    db.session.delete(post)
    db.session.commit()
    flash('게시글이 삭제되었습니다.')
    return redirect(url_for('post_list'))

 

get_or_404()를 통해 유효하지 않은 접근은 방지하고, 삭제 후에는 목록 페이지로 리다이렉트하며 플래시 메시지로 피드백을 줍니다.

③ 삭제 후 상태 확인

삭제가 완료되면 목록 페이지에서 해당 글이 사라져야 하고,

삭제된 게시글의 상세 주소로 접근할 경우 404 오류가 발생해야 해요.

이를 통해 삭제가 확실히 이루어졌는지 확인할 수 있습니다.

🧪 실습 포인트

  • 게시글 삭제 시 confirm 창이 잘 뜨는지 확인해보세요.
  • 삭제 후 목록 페이지에서 해당 글이 사라지는지 확인해보세요.
  • 삭제된 게시글 URL에 다시 접근했을 때 404 페이지가 나오는지도 꼭 확인해보세요.

이제 CRUD의 마지막 조각까지 완성되었습니다!

다음 단계에서는 전체 흐름을 다시 정리하고, CRUD를 어떻게 확장할 수 있을지에 대한 인사이트도 함께 나눠볼게요. 😊

 

 

5. CRUD 전체 사이클 정리 및 테스트 💡

지금까지 우리는 Flask와 SQLAlchemy를 활용해 게시판 CRUD 기능을 하나하나 구현해봤어요.

작성(Create), 조회(Read), 수정(Update), 삭제(Delete)까지 모든 사이클을 직접 경험하면서 웹 애플리케이션의 기본기를 탄탄하게 익혔습니다.

이 섹션에서는 전체 흐름을 다시 정리해보고, 실습 시 꼭 확인해야 할 테스트 항목들도 체크해볼게요.

① CRUD 사이클 요약 정리

기능 라우팅 설명
작성 (Create) /board/new 폼을 통해 게시글 생성, DB에 저장
조회 (Read - 목록) /board 모든 게시글을 리스트로 조회
조회 (Read - 상세) /board/<id> 단일 게시글을 ID로 조회
수정 (Update) /board/<id>/edit 기존 글을 수정하여 업데이트
삭제 (Delete) /board/<id>/delete 해당 게시글을 DB에서 삭제

② 전체 기능 테스트 체크리스트 ✅

  • 글 작성 시 제목과 내용이 비어 있으면 경고 메시지가 표시되는가?
  • 목록에서 최신 글이 가장 위에 오는가?
  • 상세 페이지에서 제목, 내용, 작성 시간이 제대로 보이는가?
  • 수정 시 기존 내용이 폼에 미리 채워지고, 수정 후 정상 반영되는가?
  • 삭제 후 목록에서 글이 사라지고, 삭제된 글 URL 접근 시 404가 나오는가?

③ 다음 단계 미리 보기 👀

CRUD 기능은 웹 애플리케이션의 핵심 기초라고 할 수 있어요.

이후에는 이 기능들을 REST API 형태로 제공하거나, JavaScript를 활용해 비동기로 처리하는 등 다양한 확장으로 이어질 수 있어요. 예를 들어:

  • 게시판을 API 형태로 만들어 React, Vue 같은 프론트엔드 프레임워크와 연동하기
  • JWT 로그인 기능과 결합해 작성자 인증/권한 부여 기능 추가하기
  • 댓글 기능, 파일 첨부 기능 등 게시판 고도화

이번 CRUD 구현이 단순한 끝이 아니라, 앞으로 나아갈 가능성의 출발점이라는 걸 꼭 기억해 주세요!

 

 

6. 마무리 및 다음 단계 안내 🚀

여기까지 따라오신 여러분 정말 수고 많으셨습니다! 👏

Flask와 SQLAlchemy를 사용한 게시판 CRUD 기능 구현을 하나하나 직접 해보며, 웹 애플리케이션 개발의 핵심 흐름을 완전히 익히셨을 거예요.

처음에는 생소했던 라우팅, 폼 데이터 처리, 데이터베이스 모델, 커밋과 쿼리 등 다양한 개념이 이제는 자연스럽게 느껴지실 겁니다.

이 CRUD 구현 경험은 이후의 모든 웹 개발 여정에 있어서 든든한 뼈대가 되어줄 거예요.

 

이번 실습을 통해 익힌 기술은 단순한 기능 구현을 넘어서, 실제 서비스를 만들고 유지보수하는 데에도 큰 도움이 됩니다.

 

그리고 여기서 끝이 아니에요!

다음 단계에서는 이 CRUD 기능들을 RESTful API로 전환하고, 프론트엔드와 연결하거나, 인증 기능을 넣는 방법도 배울 수 있어요.

웹 개발자로서 한 단계 더 도약할 수 있는 기반이 다져진 거죠. 😎

 

꼭 한 번 CRUD 기능을 자신만의 프로젝트에 적용해보세요.

예를 들어,

  • 나만의 블로그 만들기
  • 간단한 TODO 앱이나 일기장 만들기
  • Flask와 React를 연동한 게시판 프로젝트 도전하기

앞으로도 꾸준히 연습하고 발전해 나가면, 어떤 웹 서비스도 직접 만들 수 있게 될 거예요.

우리는 이제 시작입니다! 😄

반응형