์ƒˆ์†Œ์‹

๐Ÿ ํŒŒ์ด์ฌ (Python)/-- ํ”Œ๋ผ์Šคํฌ (Flask)

ํ”Œ๋ผ์Šคํฌ (Flask) ๋กœ๊ทธ์ธ , ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ (session ํ™œ์šฉ)

  • -

*์ง€๋‚œ ํฌ์ŠคํŒ… :https://infinitt.tistory.com/113?category=1071293

 

ํ”Œ๋ผ์Šคํฌ (Flask) - ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ 2 (WTF ์ด์šฉํ•˜๊ธฐ)

*Flask - WTF ์ง€๋‚œ ํฌ์ŠคํŒ…๋•Œ๋Š” ํšŒ์›๊ฐ€์ž…์‹œ ์ž…๋ ฅํ•˜์ง€ ์•Š์•˜๋˜๊ฒƒ์ด ์žˆ๋Š”์ง€, ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‘๋ฒˆ ์ž…๋ ฅํ• ๋•Œ ๋‹ค๋ฅด๊ฒŒ ์ž…๋ ฅํ•˜์ง„ ์•Š์•˜๋Š”์ง€ if๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜๋™์ ์œผ๋กœ Validation์„ ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” WTF๋ฅผ ์ด์šฉํ•˜์—ฌ..

infinitt.tistory.com

 

ํด๋ผ์ด์–ธํŠธ(์‚ฌ์šฉ์ž)์™€ ์„œ๋ฒ„๊ฐ€ ์ •๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ์ฟ ํ‚ค(Cookie)์™€ ์„ธ์…˜(session).

์ฟ ํ‚ค๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์†Œ๋ฉธํ•˜๊ณ , ์„œ๋ฒ„์˜ ์ž์›์„ ํ™œ์šฉํ•˜์ง€ ์•Š๊ณ  ํด๋ผ์ด์–ธํŠธ์ชฝ์— ์ €์žฅ๋œ๋‹ค.  ๋”ฐ๋ผ์„œ ๋กœ๊ทธ์ธ๊ณผ ๊ฐ™์€ ๋ณด์•ˆ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ• ๋•Œ๋Š” ์„ธ์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค. 

ํ”Œ๋ผ์Šคํฌ์—์„œ๋Š” ์„ธ์…˜์„ ๋”•์…”๋„ˆ๋ฆฌํ˜•ํƒœ๋กœ ์ œ๊ณตํ•œ๋‹ค. (์ฆ‰, Key๊ฐ’์„ ํ†ตํ•ด Value๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”,,) 

๋”ฐ๋ผ์„œ ์„ธ์…˜๊ณผ, ํšŒ์›๊ฐ€์ž…๋•Œ ๋ฐ›์•„๋‘์—ˆ๋˜ DB์˜ id ํ•„๋“œ , password ํ•„๋“œ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค.

๋ฐ˜๋Œ€๋กœ, ๋กœ๊ทธ์•„์›ƒ์€ ์„ธ์…˜์„ ์ œ๊ฑฐํ•˜๋ฉด ๋. (pop์ด๋‚˜ remove)

 

 

* ํ”Œ๋ผ์Šคํฌ์—์„œ์˜ session ์‚ฌ์šฉ

from flask import session 

์ผ๋‹จ import๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 


*๊ตฌ์กฐ (Structure)

Flaskํด๋”
โ”‚   โ”œโ”€โ”€ templates (ํด๋”)
โ”‚          โ”œโ”€โ”€ register.html                                    
โ”‚          โ”œโ”€โ”€ login.html       
โ”‚          โ”œโ”€โ”€ hello.html 
โ”œโ”€โ”€ app.py (์‹คํ–‰ํŒŒ์ผ)                                           
โ”œโ”€โ”€ db.sqlite
โ”œโ”€โ”€ models.py

โ”œโ”€โ”€ forms.py        (ํŒŒ๋ž€์ƒ‰์€ ์ด๋ฒˆํฌ์ŠคํŒ…์—์„œ ๋ณ€๊ฒฝํ•  ํŒŒ์ผ๋“ค)


*๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

*login.html

<html>
    <head>
        <meta charset='utf-8'/>
        <meta name='viewport' content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
    
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
     integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
     integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous">
     </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
     integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous">
     </script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
     integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
     </script>
    </head>

<body>
  
    <div class="container">
        <div class="row mt-5">
            <h1>๋กœ๊ทธ์ธ</h1>
        </div>
        <div class="row mt-5">
            <div class="col-12">
                <form method="POST" >   
                    {{form.csrf_token}}
                    <div class="form-group">
                        
                        {{form.userid.label("์•„์ด๋””")}}
                        {{form.userid(class="form-control", placeholder="์•„์ด๋””")}}
                    </div>
                    
                    <div class="form-group">
                       
                        {{form.password.label("๋น„๋ฐ€๋ฒˆํ˜ธ")}}
                        {%if form.password.errors%}  
                        <!-- ๋กœ๊ทธ์ธ ์‹คํŒจ์‹œ errors/ passwordํ•„๋“œ์˜ ๋ชจ๋“  ์—๋Ÿฌ๋ฅผ ๊ฐ–๊ณ ์žˆ๋‹ค. -->
                        {{form.password.errors.0}}
                        <!--0 : ์ฒซ๋ฒˆ์งธ ์—๋Ÿฌ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅ ํ•˜๊ฒ ๋‹ค ๋ผ๋Š” ๋œป  -->
                        {%endif%}
                        {{form.password(class="form-control", placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ")}}
                        
                    </div>
                    
                    <button type="submit" class="btn btn-primary">๋กœ๊ทธ์ธ</button>
                </form>
            </div>

        </div>
    </div>
</body>
</html>

์ง€๋‚œ ํฌ์ŠคํŒ…๋•Œ ๋งŒ๋“ค์—ˆ๋˜ ํšŒ์›๊ฐ€์ž… ํผ์—์„œ ํ•„์š”์—†๋Š” ๋ถ€๋ถ„์„ ์‚ญ์ œํ•˜์—ฌ ๋งŒ๋“ญ๋‹ˆ๋‹ค. (์‚ฌ์šฉ์ž์ด๋ฆ„, ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌํ™•์ธ์€ ํ•„์š” X)

*app.py

import os #์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•œ Os๋ชจ๋“ˆ ์ž„ํฌํŠธ
from flask import Flask
from flask import request #ํšŒ์›์ •๋ณด ์ œ์ถœํ–ˆ์„๋•Œ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•œ request, post์š”์ฒญ์„ ํ™œ์„ฑํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•จ
from flask import redirect   #ํŽ˜์ด์ง€ ์ด๋™์‹œํ‚ค๋Š” ํ•จ์ˆ˜
from flask import render_template
from models import db
from models import Fcuser 
from flask import session 
from flask_wtf.csrf import CSRFProtect
from forms import RegisterForm, LoginForm

app = Flask(__name__)

@app.route('/register', methods=['GET','POST'])  #๊ฒŸ, ํฌ์ŠคํŠธ ๋ฉ”์†Œ๋“œ ๋‘˜๋‹ค ์‚ฌ์šฉ
def register():   #get ์š”์ฒญ ๋‹จ์ˆœํžˆ ํŽ˜์ด์ง€ ํ‘œ์‹œ post์š”์ฒญ ํšŒ์›๊ฐ€์ž…-๋“ฑ๋ก์„ ๋ˆŒ๋ €์„๋•Œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๋Š”๊ฒƒ
    form = RegisterForm()
    if form.validate_on_submit(): # POST๊ฒ€์‚ฌ์˜ ์œ ํšจ์„ฑ๊ฒ€์‚ฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž…๋ ฅ ์•ˆํ•œ๊ฒƒ๋“ค์ด ์žˆ๋Š”์ง€ ํ™•์ธ๋จ.
        #๋น„๋ฐ€๋ฒˆํ˜ธ = ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ -> EqulaTo
    
        fcuser = Fcuser()  #models.py์— ์žˆ๋Š” Fcuser 
        fcuser.userid = form.data.get('userid')
        fcuser.username = form.data.get('username')
        fcuser.password = form.data.get('password')
            
        print(fcuser.userid,fcuser.password)  #ํšŒ์›๊ฐ€์ž… ์š”์ฒญ์‹œ ์ฝ˜์†”์ฐฝ์— ID๋งŒ ์ถœ๋ ฅ (ํ™•์ธ์šฉ, ๋”ฑํžˆ ํ•„์š”์—†์Œ)
        db.session.add(fcuser)  # id, name ๋ณ€์ˆ˜์— ๋„ฃ์€ ํšŒ์›์ •๋ณด DB์— ์ €์žฅ
        db.session.commit()  #์ปค๋ฐ‹
        return "๊ฐ€์ž… ์™„๋ฃŒ" #post์š”์ฒญ์ผ์‹œ๋Š” '/'์ฃผ์†Œ๋กœ ์ด๋™. (ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ์‹œ ํ™”๋ฉด์ด๋™)
    return render_template('register.html', form=form)

@app.route('/login', methods=['GET','POST'])  
def login():  
    form = LoginForm() #๋กœ๊ทธ์ธ ํผ ์ƒ์„ฑ
    if form.validate_on_submit(): #์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
        session['userid'] = form.data.get('userid') #form์—์„œ ๊ฐ€์ ธ์˜จ userid๋ฅผ session์— ์ €์žฅ
    
        
        return redirect('/') #๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜๋ฉด ํ™ˆํ™”๋ฉด์œผ๋กœ redirect
            
    return render_template('login.html', form=form)

@app.route('/')
def hello():
    userid = session.get('userid', None)
    return render_template('hello.html',userid=userid)    # ์ด๋ฒˆ ํฌ์ŠคํŒ…์—๋Š” ํ•„์š”์—†์Œ(์ง€๋‚œํฌ์ŠคํŒ…๊บผ)

if __name__ == "__main__":
    basedir = os.path.abspath(os.path.dirname(__file__)) #dbํŒŒ์ผ์„ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์ƒ์„ฑ
    dbfile = os.path.join(basedir, 'db.sqlite')#dbํŒŒ์ผ์„ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์ƒ์„ฑ

    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + dbfile   
#sqlite๋ฅผ ์‚ฌ์šฉํ•จ. (๋งŒ์•ฝ mysql์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, id password ๋“ฑ... ๋” ํ•„์š”ํ•œ๊ฒŒ๋งŽ๋‹ค.)
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 
#์‚ฌ์šฉ์ž ์š”์ฒญ์˜ ๋๋งˆ๋‹ค ์ปค๋ฐ‹(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ,์ˆ˜์ •,์‚ญ์ œ๋“ฑ์˜ ๋™์ž‘์„ ์Œ“์•„๋†จ๋˜ ๊ฒƒ๋“ค์˜ ์‹คํ–‰๋ช…๋ น)์„ ํ•œ๋‹ค.
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 
#์ˆ˜์ •์‚ฌํ•ญ์— ๋Œ€ํ•œ track์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. True๋กœ ํ•œ๋‹ค๋ฉด warning ๋ฉ”์‹œ์ง€์œ ๋ฐœ
    app.config['SECRET_KEY'] = 'wcsfeufhwiquehfdx'

    csrf = CSRFProtect()
    csrf.init_app(app)

    db.init_app(app)
    db.app = app
    db.create_all()  #db ์ƒ์„ฑ


    
    app.run(host='127.0.0.1', port=5000, debug=True) 
     #ํฌํŠธ๋ฒˆํ˜ธ๋Š” ๊ธฐ๋ณธ 5000, ๊ฐœ๋ฐœ๋‹จ๊ณ„์—์„œ๋Š” debug๋Š” True

 

 

*forms.py

from flask_wtf import FlaskForm
from models import Fcuser
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, EqualTo

class RegisterForm(FlaskForm):
    userid = StringField('userid', validators=[DataRequired()])
    username = StringField('username', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired(), EqualTo('re_password')]) #equalTo("ํ•„๋“œ๋„ค์ž„")
    re_password = PasswordField('re_password', validators=[DataRequired()])


class LoginForm(FlaskForm):
    class UserPassword(object):
        def __init__(self, message=None):
            self.message = message
        def __call__(self,form,field):
            userid = form['userid'].data
            password = field.data
            fcuser = Fcuser.query.filter_by(userid=userid).first()
            if fcuser.password != password:
                # raise ValidationError(message % d)
                raise ValueError('Wrong password')
    userid = StringField('userid', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired(), UserPassword()]) 
   

 

*hello.html (ํ™ˆํ™”๋ฉด)

<strong>Hello World!</strong>
{%if userid%}
{{userid}}
{%endif%}

 


ํšŒ์›๊ฐ€์ž…์„ ํ–ˆ์—ˆ๋˜ ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•ด์•ผ๋งŒ ๋กœ๊ทธ์ธ์ด ๋ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์ธ์ด ์„ฑ๊ณต๋˜๋ฉด redirect('/')์— ์˜ํ•ด์„œ ํ™ˆํ™”๋ฉด์œผ๋กœ ์ด๋™๋˜๊ณ , Hello + ์‚ฌ์šฉ์ž ์•„์ด๋”” ๊ฐ€ ํ™”๋ฉด์— ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.


*๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

 

๋กœ๊ทธ์•„์›ƒ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ›์•˜๋˜ ์„ธ์…˜์„ ์‚ญ์ œํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค.

*app.py์— ์ถ”๊ฐ€

@app.route('/logout',methods=['GET'])
def logout():
    session.pop('userid',None)
    return redirect('/')

*hello.html (ํ™ˆํ™”๋ฉด์— ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ ์ƒ์„ฑํ•˜๊ธฐ)

<strong>Hello World!</strong>
{%if userid%}
{{userid}} <button type="button" onclick="location.href='/logout' ">๋กœ๊ทธ ์•„์›ƒ</button> 
{%endif%}

 

 

 

๋กœ๊ทธ์ธ ํ™”๋ฉด

๋กœ๊ทธ์•„์›ƒ์„ ๋ˆ„๋ฅด๊ฒŒ ๋˜๋ฉด

์‚ฌ์šฉ์ž ID์™€ ๋กœ๊ทธ์•„์›ƒ button์ด ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.