본문 바로가기

Programming/python

Flask를 이용해서 나만의 웹 서버 구축하기(feat.사우스 파크)

728x90
반응형

안녕 친구들 (빡빡이)그냥 아조씨야!

 

오늘은 Flask 웹 프레임워크를 이용해서

 

회원가입과 로그인이 가능하고 접속을 하면 게시판까지 작성할 수 있는 

나만의 웹 서버를 구현할 거야!


우선 오늘의 포인트는

html 파일을 만들어 페이지를 구현할 때는
반드시 잊지말고 templates 폴더에 저장하자!

 

 

 

 

1. 홈 페이지 만들기

 


사우스 파크를 매우 열렬히 좋아하고 사랑하기 때문에 사팤 팬 페이지를 만들 거임 ㅇㅇ.

 

우선 index.html 파일을 이용하여 첫 메인 페이지를 만든다.

 

 후에 render_template 모듈 사용을 위해 templates라는 폴더를 생성하고 그 안에

index.html(홈페이지), login.html, loggedin(로그인 구현 페이지), register.html(회원 등록 페이지), board.html(게시물 페이지)을 만들어 보자.

 

우선 홈페이지를 담당 할 index.html 파일이다.

반드시!!!! 잊지말고 templates 파일에 생성해주자!!!

<!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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <div>
        <img src="https://ww.namu.la/s/b8d686cd9c35225957c823ad209dfc4da13fef8ce358835b3e3cff0335bb1cbe6c52f956404911f9a05b96b827cd4a495bbe2408a0165c5b4bf70dd434af8cd00a89d98ff604549b5213842d11006bd52b0e85b18484f3a9123439366ca1aad8dda89d911150a6b4d6041902d755ffe7">
    </div>
    <div>
        <p>
            Are you a fan of South Park?
        </p>
        <a href="register">
            REGIST
        </a>
        <br></br>
        <a href="login">
            LOGIN
        </a>
    </div>
</body>
</html>

 

 

여기서 주의할 점은

 

a 태그에 링크를 걸어주는데 index.html, 즉 파일명을 직접 입력하는 것이 아니라,

flask에서 동작 될 서버 url의 리소스 경로로 지정해 주어야 한다.

안 그러면 인식 못하고 자꾸 서버인데 로컬에 있는 파일로 접속하려 한다. 물론 접속은 안된다. 오류 뜬다 404

 

 

여기도 마찬가지다 regiset.html, login.html이 아니라 리소스 경로로 지정해준다.

(이거 때문에 1시간 잡아먹었다...)

 

 

 

짜잔 홈페이지가 완성 되었다.

 

 

얼추 이렇게 페이지 구성이 완료되었으면 main.py(파일명은 상관없음)을 만들어 준다.

 

이거는 templates에 넣는 거 아니다!!!!!!!!!!!!!!!!!!

넣지마라!!!!!!!!!!!!!!!!! 절대!!!!!!!!!!!!!! 넣지 마!!!!!!!!!!!!

 

@app.route("/")
def homepage():
    if session.get('logged_in') :
        return render_template('loggedin.html')
    else:
        return render_template('index.html')

우선 홈페이지이기 때문에 route값에 '/'(대충 제일 앞 페이지라는 의미)를 주고 homepage 함수를 구현했다.

 

대강 이런 의미다.

'만약 로그인이 성공했으면 혹은 성공한 상태면, 로그인 한 페이지를 열어주고

그렇지 않다면 걍 이 놈한테는 홈페이지나 열어줘라'

 

 

 

 

2. 회원 등록 페이지 구현하기


다음 단계는 회원 가입하는 페이지를 구현하기다.

 

코드는 다음과 같다.

<!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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <form action="" method="post">
        <p>ID : <input type="text" id = "username" name="username"></p>
        <p>PWD : <input type="password" id = "password" name="password"></p>
        <p>
            Please input your ID and Password for registering and click the button below<br>
            <input type="submit" value="SUBMIT">
        </p>
    </form>
</body>
</html>

 

 

여기서 주의해야 할 코드는 

<form> 태그이다.

폼 태그로 다른 페이지로 보낼 정보를 입력한 태그들을 감싸줘야 한다.

또한 폼 태그 안에 action을 작성해 데이터를 보낼 url을 지정해 줘야 하는데,

약식으로 원리를 파악하고 일일이 지정하기 귀찮기 때문에 빈 값으로 작성하겠다.

하지만 서버에 http 전송 방식을 입력하는 method의 값은 비우면 안 된다.

get이나 post가 들어갈 수 있는데, id와 pwd는 url 정보에 표시되면 안 되기 때문에 이건 post의 값을 넣는다.

 

 

 

너의 아이디와 비밀번호를 입력하고 아래 버튼을 눌러라

 

 

다시 main.py 파일을 열어 

userinfo = {'fu': 'fu'}

@app.route('/register', methods=['GET', 'POST'])
def regist():
    if request.method == 'POST':
        userinfo[request.form['username']] = request.form['password']
        return redirect(url_for('login'))
    else:
        return render_template('register.html')

맨 위 우선 사용자의 데이터가 담길 userinfo 변수를 딕셔너리 값으로 초기화해준다.(fu는 신경 안 써도 된다)

route의 값은 register로 지정해주고받는 메소드들을 get과 post를 넣어준다.

그러고 나서 regist함수를 구현한다. 

만약 클라이언트에서 포스트의 요청이 오면 서버에 있는 userinfo의 값을 요청한 대로 바꿔 주고

바로 로그인 창으로 전환한다. 근데 등록에서 실패하면 그대로 다시 하게 냅둬라.

 

 

등록이 완료되면 바로 로그인 페이지로 이동한다.

 

 

 

 

3. 로그인 화면 구현하기


사용자 등록까지 완료했다면 이제는 로그인을 할 차례다. 로그인이 진행되는 로그인 페이지를 구현하자.

 

<!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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div>
    <form action="" method="post">
        <p>ID : <input type="text" id = "username" name="username"></p>
        <p>PWD : <input type="password" id = "password" name="password"></p>
        <p>
            Please insert your ID and Password for loggin and click the button below<br>
            <input type="submit" value="LOGIN">
        </p>
    </form>
</body>
</html>

 

 

 

니가 등록한 아이디와 비밀번호를 입력하고 눌러라~

 

 

 

여기까지 구현이 됐다면 다시 파이썬 파일로 돌아와서

 

 

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        name = request.form['username']
        password = request.form['password']
        try:
            if name in userinfo:
                if userinfo[name] == password:
                    session['logged_in'] = True
                    return redirect(url_for('homepage'))
                else:
                    return 'Wrong Password!'
            return 'ID does not exist'
        except:
            return 'Don\'t login'
    else:
        return render_template('login.html')

 

login 함수를 구현해 준다.

post의 요청이 들어오면 아까 작성한 폼에 id와 비밀번호를

userinfo에 등록된 사용자와 일치하는지 확인한다.

만약 입력한 비밀번호가 같으면 세션 값을 true로 변경하고

url_for 함수로 지정된 homepage 값으로 창을 변경한다.

 

 

 

여기서 주의할 점이!!! 아까 

 

homepage 함수

 

homepage 함수를 작성할 때,

session의 값이 ture로 지정되면 로그인 한 거로 치고

로그인 하기 전인 index.html 페이지로 가는 것이 아니라 loggedin.html로 지정했기 때문에

로그인 한 후로는 기본 홈페이지가 원래 제일 앞 페이지인 index.html이 아니라 loggedin.html로 변경된다.

 

밑에 있는 코드들은 그냥 비번이 틀리면 wrong password를 출력하고

id의 값이 없다면 id does not exist를 출력한다.

그리고 예외 사항이 발생하면 그냥 니는 로그인하지 마세요를 반환하고 다시 로그인 창에 머문다.

 

 

 

등록된 아이디가 존재하지 않으면

 

 

 

 

 

 

 

아이디는 등록되어 있지만 비밀번호가 틀리다면

 

 

 

 

 

 

 

 

 

 

4. 로그인 완료한 후 게시판을 활용할 수 있는 페이지 구현하기


 

 

<!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>South Park Fan Page</title>
    <script>
        function init()
        {
            alert('You\'ve logged in successfully!')
        }
    </script>
</head>
<body onload="init()">
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <div>
        <img src="https://ww.namu.la/s/b8d686cd9c35225957c823ad209dfc4da13fef8ce358835b3e3cff0335bb1cbe6c52f956404911f9a05b96b827cd4a495bbe2408a0165c5b4bf70dd434af8cd00a89d98ff604549b5213842d11006bd52b0e85b18484f3a9123439366ca1aad8dda89d911150a6b4d6041902d755ffe7">
    </div>
    <form action="" method="post">
        <p>
            You are loggined now. You can post.<br>
            <input type="button" value="POST" onclick="location.href='board'">
        </p>
        <p>
            <input type="button" value="LOGOUT" onclick="location.href='/logout'">
        </p>
    </form>
</body>
</html>

우선 스크립트 함수를 이용해 로그인이 성공해 페이지로 이동한다면

You've logged in successfully 메시지를 통해 로그인의 성공을 알려준다.

 

아이디와 패스워드가 정확하다면 로그인이 성공했다는 알림과 loggedin페이지로 변경된다.

 

그리고 onclick 속성을 활용해서 POST 버튼을 누르면 게시판의 페이지로 이동하고,

logout 버튼을 누르면 logout 함수를 통해 맨 앞의 페이지인 index.html로 보낸다.

 

 

 

 

@app.route("/logout")
def logout():
    session['logged_in'] = False
    return render_template('index.html')

여기서는 이제 로그아웃 함수를 구현해 주자.

로그아웃 버튼을 누르면 세션 값이 false로 변경되고 맨 앞의 홈페이지인 index.html로 보내준다.

 

 

로그아웃시 바로 index.html 페이지로 연결

 

 

 

 

 

5. 게시판 페이지 구현하기


 

<!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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <div>
        <img src="https://ww.namu.la/s/b8d686cd9c35225957c823ad209dfc4da13fef8ce358835b3e3cff0335bb1cbe6c52f956404911f9a05b96b827cd4a495bbe2408a0165c5b4bf70dd434af8cd00a89d98ff604549b5213842d11006bd52b0e85b18484f3a9123439366ca1aad8dda89d911150a6b4d6041902d755ffe7">
    </div>
    <div>
        <h1>POST ANY TEXT</h1>
        <form action="/add" method="POST">
            Your nickname
            <br>
            <input type="text" name="name">
            <br><br>
            Write your text
            <br>
            <textarea name="context" cols="40" rows="10"></textarea>
            <br>
            <input type = "submit" value = "POST"><br>
        </form>
        <h4>BOARD</h4>
        <table class="table" style = "word-break:break-all" style="table-layout: fixed">
            <thread>
                <th>#</th>
                <th>nickname</th>
                <th>context</th>
            </thread>
            {% for row in rows %}
            <tr>
                <td>{{ loop.index }}</td>
                <td>{{ row[0] }}</td>
                <td>{{ row[1] }}</td>
            </tr>
            {% endfor %}
        </table>
    </div>
</body>
</html>

 

이 코드에서는 테이블 클래스를 작성하여

각 열에 #(게시글 순서), nickname(사용자 이름), context(게시글 내용)을 넣어주고

행에는 for문을 돌려

loop.index에 각 게시글 순서를 오름 차순으로, row[0] 에는 사용자 이름 row[1]에는 게시글 내용을 넣어준다.

 

 

마지막으로 파이썬 파일로 돌아와

board = []

@app.route('/board')
def loggedin_board():
    return render_template('board.html', rows = board)

우선 각 행을 담을 board 변수 생성 후, post 버튼을 누를 시 board.html로 이동하는 함수를 구현한다.

 

 

포스트 버튼을 누르면 게시판 활성화!

 

 

@app.route('/add', methods = ['POST'])
def Board():
    if request.method == 'POST':
        board.append([request.form['name'], request.form['context']])
        return redirect(url_for('loggedin_board'))
    else:
        return render_template('board.html', rows = board)

마지막으로 보드에 내용을 추가하는 함수를 구현한다.

post 요청이 오면 입력받은 값들을 board 변수에 추가한다.

 

 

kyle: you killed kenny you bastard!

 

이제 모든 게 끝났다.

완성 본의 코드는 다음과 같다.

 

#main.py
from flask import Flask, render_template, session, url_for, redirect, request

app = Flask(__name__)
app.secret_key = 'this is super key'
app.config['SESSION_TYPE'] = 'filesystem'
userinfo = {'fu': 'fu'}
board = []

@app.route("/")
def homepage():
    if session.get('logged_in') :
        return render_template('loggedin.html')
    else:
        return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        name = request.form['username']
        password = request.form['password']
        try:
            if name in userinfo:
                if userinfo[name] == password:
                    session['logged_in'] = True
                    return redirect(url_for('homepage'))
                else:
                    return 'Wrong Password!'
            return 'ID does not exist'
        except:
            return 'Don\'t login'
    else:
        return render_template('login.html')

@app.route('/register', methods=['GET', 'POST'])
def regist():
    if request.method == 'POST':
        userinfo[request.form['username']] = request.form['password']
        return redirect(url_for('login'))
    else:
        return render_template('register.html')

@app.route("/logout")
def logout():
    session['logged_in'] = False
    return render_template('index.html')

@app.route('/board')
def loggedin_board():
    return render_template('board.html', rows = board)


@app.route('/add', methods = ['POST'])
def Board():
    if request.method == 'POST':
        board.append([request.form['name'], request.form['context']])
        return redirect(url_for('loggedin_board'))
    else:
        return render_template('board.html', rows = board)


if __name__ == '__main__':
    app.run(debug=True)
<!-- index.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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <div>
        <img src="https://ww.namu.la/s/b8d686cd9c35225957c823ad209dfc4da13fef8ce358835b3e3cff0335bb1cbe6c52f956404911f9a05b96b827cd4a495bbe2408a0165c5b4bf70dd434af8cd00a89d98ff604549b5213842d11006bd52b0e85b18484f3a9123439366ca1aad8dda89d911150a6b4d6041902d755ffe7">
    </div>
    <div>
        <p>
            Are you a fan of South Park?
        </p>
        <a href="register">
            REGIST
        </a>
        <br></br>
        <a href="login">
            LOGIN
        </a>
    </div>
</body>
</html>
<!-- register.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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <form action="" method="post">
        <p>ID : <input type="text" id = "username" name="username"></p>
        <p>PWD : <input type="password" id = "password" name="password"></p>
        <p>
            Please input your ID and Password for registering and click the button below<br>
            <input type="submit" value="SUBMIT">
        </p>
    </form>
</body>
</html>
<!-- login.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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div>
    <form action="" method="post">
        <p>ID : <input type="text" id = "username" name="username"></p>
        <p>PWD : <input type="password" id = "password" name="password"></p>
        <p>
            Please insert your ID and Password for loggin and click the button below<br>
            <input type="submit" value="LOGIN">
        </p>
    </form>
</body>
</html>
<!-- loggedin.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>South Park Fan Page</title>
    <script>
        function init()
        {
            alert('You\'ve logged in successfully!')
        }
    </script>
</head>
<body onload="init()">
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <div>
        <img src="https://ww.namu.la/s/b8d686cd9c35225957c823ad209dfc4da13fef8ce358835b3e3cff0335bb1cbe6c52f956404911f9a05b96b827cd4a495bbe2408a0165c5b4bf70dd434af8cd00a89d98ff604549b5213842d11006bd52b0e85b18484f3a9123439366ca1aad8dda89d911150a6b4d6041902d755ffe7">
    </div>
    <form action="" method="post">
        <p>
            You are loggined now. You can post.<br>
            <input type="button" value="POST" onclick="location.href='board'">
        </p>
        <p>
            <input type="button" value="LOGOUT" onclick="location.href='/logout'">
        </p>
    </form>
</body>
</html>
<!-- board.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>South Park Fan Page</title>
</head>
<body>
    <div>
        <h1 style="display: inline-block"><a href="/">This web page</a> is only for people who love</h1> <h1 style="color:pink; display: inline-block;">SOUTH PARK</h1>
    </div> 
    <div>
        <img src="https://ww.namu.la/s/b8d686cd9c35225957c823ad209dfc4da13fef8ce358835b3e3cff0335bb1cbe6c52f956404911f9a05b96b827cd4a495bbe2408a0165c5b4bf70dd434af8cd00a89d98ff604549b5213842d11006bd52b0e85b18484f3a9123439366ca1aad8dda89d911150a6b4d6041902d755ffe7">
    </div>
    <div>
        <h1>POST ANY TEXT</h1>
        <form action="/add" method="POST">
            Your nickname
            <br>
            <input type="text" name="name">
            <br><br>
            Write your text
            <br>
            <textarea name="context" cols="40" rows="10"></textarea>
            <br>
            <input type = "submit" value = "POST"><br>
        </form>
        <h4>BOARD</h4>
        <table class="table" style = "word-break:break-all" style="table-layout: fixed">
            <thread>
                <th>#</th>
                <th>nickname</th>
                <th>context</th>
            </thread>
            {% for row in rows %}
            <tr>
                <td>{{ loop.index }}</td>
                <td>{{ row[0] }}</td>
                <td>{{ row[1] }}</td>
            </tr>
            {% endfor %}
        </table>
    </div>
</body>
</html>

 

728x90
반응형