본문 바로가기

웹개발

게시판(flask)-CRUD

우선 글을 저장하기 위한 테이블을 mysql에서 만들어줘야 한다.

mysql> CREATE TABLE posts (
    ->   id INT AUTO_INCREMENT PRIMARY KEY,
    ->   title VARCHAR(255),
    ->   content TEXT
    -> );

이렇게 만들었었는데 글을 쓴 username도 있어야 한다는 사실을 뒤늦게 깨달아서 

 ALTER TABLE posts ADD COLUMN username VARCHAR(255);

이걸로 username 속성까지 추가해 주었다.

 

CRUD 기능을 만들기 전에 먼저

@app.route('/board')
def board():
    conn = connectsql()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    query = "SELECT id, title, content FROM posts ORDER BY id DESC"
    cursor.execute(query)
    post = cursor.fetchall()
    
    cursor.close()
    conn.close()

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

board 링크에서 글 목록을 볼 수 있게 해주는 페이지를 먼저 만들었다.

id를 기준으로 역순으로 정렬해서 최신 글이 위에 있도록 목록을 만들었다.

post를 board.html 파일로 넘겨주었다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판</title>
</head>
<body>
    <h1>게시글 목록</h1>
    <ul>
        {% for post in post %}
            <li><a href="{{ url_for('read', id=post.id) }}">{{ post.title }}</a></li>
        {% endfor %}
    </ul>
    <a href="{{ url_for('write') }}">글 작성</a>
</body>
</html>

board.html 파일에는 글 목록을 클릭해서 read 페이지로 넘어가는 것과 글 작성 링크를 넣어두었다.

 

<read>

@app.route('/board/read/<id>')
def read(id):
    if 'username' in session:
        username = session['username']

        conn = connectsql()
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        query = "SELECT id, title, content, username FROM posts WHERE id = %s"
        value = id
        cursor.execute(query, value)
        post = cursor.fetchone()
        iswriter = False
        if post['username'] == username:
            iswriter = True
        conn.commit()
        cursor.close()
        conn.close()
        return render_template('read.html', post = post, iswriter = iswriter)
    else:
        redirect(url_for('login'))

read 링크에서는 mysql 조회를 통해 데이터를 post로 가져온다. 그리고 session에 저장된 username을 이용해

글을 쓴 사람이라면 iswriter를 True로 만들고 read.html에 같이 넘겨준다.

만약 로그인이 안된 상태라면 글을 보지 못하고 login창으로 이동시킨다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ post.title }}</title>
</head>
<body>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
    {% if iswriter %}
    <a href="{{ url_for('edit', id=post.id) }}">수정</a>
    <a href="{{ url_for('delete', id=post.id) }}" onclick="return confirm('정말 삭제하시겠습니까?');">삭제</a>
    {% endif %}
    <a href="{{ url_for('board') }}">목록으로</a>
</body>
</html>

read.html에서는 글을 보여주는데 iswriter가 True라면 수정과 삭제 링크가 보이도록 만들었다.

 

 

<write>

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

            conn = connectsql()
            cursor = conn.cursor()
            query = "INSERT INTO posts (title, content, username) values (%s, %s, %s)"
            value = (title, content, username)
            cursor.execute(query, value)
            conn.commit()
            cursor.close()
            conn.close()

            return redirect('/')
        else:
            return redirect(url_for('login'))
    else:
        if 'username' in session:
            return render_template ('write.html')
        else:
            return redirect(url_for('login'))

로그인이 안 되어 있으면 로그인 창으로 이동시킨다.

INSERT 문으로 title, content, username을 posts 테이블에 넣는다.

GET 방식 요청에는 write.html을 렌더링한다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>글 작성</title>
</head>
<body>
    <h1>글 작성</h1>
    <form method="post" action="/board/write">
        <label for="title">제목</label>
        <input type="text" id="title" name="title" required>
        <br>
        <label for="content">내용</label>
        <textarea id="content" name="content" required></textarea>
        <br>
        <button type="submit">작성</button>
    </form>
    <a href="{{ url_for('index') }}">취소</a>
</body>
</html>

 

<edit>

@app.route('/board/edit/<id>', methods=['GET', 'POST'])
def edit(id):
    if request.method == 'POST':
        if 'username' in session:
            username = session['username']
 
            edittitle = request.form['title']
            editcontent = request.form['content']

            conn = connectsql()
            cursor = conn.cursor()
            query = "UPDATE posts SET title = %s, content = %s WHERE id = %s"
            value = (edittitle, editcontent, id)
            cursor.execute(query, value)
            conn.commit()
            cursor.close()
            conn.close()
    
            return redirect(url_for('board'))
    else:
        username = session['username']
        conn = connectsql()
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        query = "SELECT id, title, content FROM posts WHERE id = %s"
        value = id
        cursor.execute(query, value)
        post = cursor.fetchone()
        cursor.close()
        conn.close()
        if username in post:
            return render_template('edit.html', post = post)

GET 방식 요청에서는 현재 로그인된 사용자가 게시글의 작성자와 일치하면 edit.html을 렌더링하고

POST 방식 요청에서는 title과 content를 받아서 UPDATE 구문으로 데이터를 업데이트한다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ post.title }} - 수정</title>
</head>
<body>
    <h1>{{ post.title }} - 수정</h1>
    <form method="post">
        <label for="title">제목</label>
        <input type="text" id="title" name="title" value="{{ post.title }}" required>
        <br>
        <label for="content">내용</label>
        <textarea id="content" name="content" required>{{ post.content }}</textarea>
        <br>
        <button type="submit">수정</button>
    </form>
    <a href="{{ url_for('read', id=post.id) }}">취소</a>
</body>
</html>

edit.html 파일은 write.html 파일과 거의 유사하다.

 

<delete>

@app.route('/board/delete/<id>')
def delete(id):
    if 'username' in session:
        username = session['username']
        conn = connectsql()
        cursor = conn.cursor()
        query = "SELECT username FROM posts WHERE id = %s"
        value = id
        cursor.execute(query, value)
        data = [post[0] for post in cursor.fetchall()]
        cursor.close()
        conn.close()

        if username in data:
            conn = connectsql()
            cursor = conn.cursor()
            query = "DELETE FROM posts WHERE id = %s"
            value = id
            cursor.execute(query, value)
            conn.commit()
            cursor.close()
            conn.close()
            return redirect(url_for('board'))

delete 부분은 따로 화면 페이지 이동은 없고 로그인된 사용자가 작성자라면 DELETE 구문으로 데이터를 삭제한다.