- Flask๋ ๋ง์ดํฌ๋ก ํ๋ ์์ํฌ๋ค.
- WSGI ์๋ธ์์คํ ์ Werkzeung์, ํ ํ๋ฆฟ์ jinja2์ ์์กดํ๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ธ์คํด์ค๋ฅผ ์์ฑํด์ผ ํ๋ค.
- ์น ์๋ฒ๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ request๋ฅผ ์์ ํ๋๋ฐ ์ด๋ฅผ Flask์ ์ดํ๋ฆฌ์ผ์ด์ ์ธ์คํด์ค์์ ์ฒ๋ฆฌํ๋๋ฐ ์ด๋ WSGI ๋ผ๋ protocol์ ์ฌ์ฉํ๋ค.
- Route : URL๊ณผ URL๋ฅผ ์ฒ๋ฆฌํ๋ ํจ์์ ๊ด๋ จ์ฑ์ Route๋ผ๊ณ ํ๋ค. URL์ ํจ์์ ๋งคํํ๋ ๊ธฐ๋ฅ
- View Function : URL์ ์ฒ๋ฆฌํ๋ ํจ์๋ฅผ View Function์ด๋ผ๊ณ ํ๋ค.
- Flask์์๋ @app.route() decorator๋ก ๋ผ์ฐํธ๋ฅผ ์ ์ํด ์ค ์ ์๋ค.
- ๋์ ์ปดํฌ๋ํธ๋ @add.route('/user/') ์ ๊ฐ์ด ์ง์ ํด ์ค ์ ์๋ค
- ๋์ ์ปดํฌ๋ํธ๋ ํ์ ์ ์ ์ํด์ค ์ ์๋ค. @add.route('/user/<int: id>') int, float, path๋ฅผ ์ง์ํ๋ค.
- ๋์ ์ปดํฌ๋ํธ์ ์ ๋ ฅ ํ์ ์ด ๋ค๋ฅผ ๊ฒฝ์ฐ Not Found๋ฅผ ๋ฆฌํดํ๋ค.
- application instance๋ run ๋ฉ์๋๋ก ์น ์๋ฒ๋ฅผ ์คํํ๋ค.
- ์๋ฒ๋ฅผ ์คํํ๊ณ ๋๋ฉด ์๋ฒ๋ ๋ฃจํ๋ฅผ ์งํํ๋ค.
- ํ๋ผ์คํฌ์์ ์ ๊ณตํ๋ ์น ์๋ฒ๋ ์ ํ ์์ฐ์ ๋ชฉ์ ์ผ๋ก ํ์ง ์๋๋ค.
-
Flask๊ฐ client ์์ request๋ฅผ ์์ ํ๋ฉด ์ด๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด view function์์๋ ์ฌ๋ฌ๊ฐ์ ์ค๋ธ์ ํธ๋ฅผ ์์ฑํด์ผ ํ๋ค.
-
requests object๋ HTTP requests๋ฅผ ์บก์ํ ํ๋ค.
-
view funtion์ด request object์ ์ก์ธ์คํ ์ ์๋ ํ์คํ ๋ฐฉ๋ฒ์ ์ธ์๋ก์ ๋ฐ๋ ๊ฒ์ธ๋ฐ ์ด๋ ์ฌ๋ถ์ ์ธ์๋ฅผ ๊ฐ๋๋ก ์๊ตฌํ๋ค. request object ๋ง์ด view function์ด access ํด์ผํ๋ ์ค๋ธ์ ํธ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ธ์๋ก ๋ฐ๋ ๊ฒ์๋ ๋ฌด๋ฆฌ๊ฐ ์๋ค. view function์ด ๋ค์์ ์ค๋ธ์ ํธ๋ฅผ ์ธ์๋ก ๋ฐ๋๊ฑธ ํผํ๊ธฐ ์ํด Flask๋ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ์์์ ์ผ๋ก ์ค๋ธ์ ํธ๋ฅผ ๊ธ๋ก๋ฒํ๊ฒ ์ก์ธ์คํ๋๋ก ํ๋ค.
from flask import request @app.route('/') def index(): user_agent = request.headers.get('User-Agent') return f'<p>your brower is {user_agent} </p>'
-
๋ค์๊ณผ ๊ฐ์ context ๋ค์ด ์๋ค 17.p
โ current_app : ํ์ฑํ๋ app์ ์ํ app instance
โ g : request ๋ง๋ค ์์ฑ๋๋ ์์ ์คํ ๋ฆฌ์ง ์ค๋ธ์ ํธ
โ request : HTTP request context๋ฅผ ์บก์ํ ํ๋ ์ค๋ธ์ ํธ
โ session : ์ฌ์ฉ์ ์ธ์
-
ํด๋ผ์ด์ธํธ์์ request๋ฅผ ์์ ํ๋ฉด ๊ทธ๊ฒ์ ์๋น์คํ๊ธฐ ์ํ view function์ URL์ ํตํด ์ฐพ๋๋ค. ์ด๋ URL map์์ ์ด๋ฅผ ์ฐพ๋๋ค. ํ์ด์ฌ ํ์ผ์ด๋ฆ์ด practice.py ๋ผ๊ณ ํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฐพ์ ์ ์๋ค.
$ python >>> from practice import app >>> app.url_map Map([<Rule '/' (OPTIONS, HEAD, GET) -> index>, <Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>, <Rule '/user/<name>' (OPTIONS, HEAD, GET) -> user>])
-
request๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ ํ์ ์ฝ๋๋ฅผ ๋์์์ผ์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. DB connection, ์ฌ์ฉ์ ์ธ์ฆ ๊ฐ์ ๊ฒฝ์ฐ๋ค.
-
Flask๋ request hooks๋ฅผ ๋ฐ์ฝ๋ ์ดํฐ ํํ๋ก ์คํํ๋๋ก ํ๊ณ ๋ค์๊ณผ ๊ฐ์ 4๊ฐ์ ์ข ๋ฅ๊ฐ ์๋ค
โ before_first_request
โ before_request
โ after_request
โ tesrdown_request
-
Request Hooks function๊ณผ View function ์ฌ์ด์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๊ธฐ ์ํด g context ์ ์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ค.
-
Flask๋ 200์ ๊ธฐ๋ณธ ์ํ ์ฝ๋๋ก ์๋ตํ๋ค.
-
200 ์ด์ธ์ ์ํ์ฝ๋๋ฅผ ๋ฆฌํดํ ๋๋ ์๋์ ๊ฐ์ด return์ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
@app.route('/') def index(): return '<h1>Bad Requests</h1>', 400
-
Response object๋ฅผ returnํด์ค์๋ ์๋ค. ์ด๋๋ ์๋ต ์ค์ ์ด ๊ฐ๋ฅํ๋ค๋ ์ฅ์ ์ด ์๋ค.
-
์๋์ฝ๋๋ ์ฟ ํค๋ฅผ ์ค์ ํ๊ณ Response object๋ฅผ return ํ๋ ์์ด๋ค.
from flask import make_response
@app.route('/')
def index():
response = make_response('<h1>This document carries a cookie </h1>')
response.set_cookie('answer', '42')
return response
-
์๋ต์ ํ ์ข ๋ฅ์ด๋ค.
-
page document๋ฅผ ํฌํจํ์ง ์์ผ๋ฉฐ ์๋ก์ด page๋ฅผ ๋ก๋ํ๋ ์๋ก์ด URL์ ๋ธ๋ผ์ฐ์ ์ ์ ๋ฌํ๋ค.
-
Flask๋ redirect ํจ์๋ฅผ ์ ๊ณตํ๋ค
from flask import redirect @app.route('/') def index(): return redirect('http://www.example.com')
-
์๋ต์ฝ๋๋ 302 ์ด๋ค.
-
Flask-Script
โ ์ปค๋งจ๋ ๋ผ์ธ ํ์๋ฅผ ์ถ๊ฐํ๋ ํ์ฅ
โ Flask์ startup ์ค์ ์ต์ ์ ์ปค๋งจ๋ ๋ผ์ธ์์ ์กฐ์ ํ๊ฒ ํด์ค๋ค.์ฆ, app.run() ํธ์ถ์ ์ธ์๋ฅผ ์ปค๋งจ๋ ๋ผ์ธ์์ ์กฐ์ ๊ฐ๋ฅํ๊ฒ ํด์ค๋ค.
โ ๊ทผ๋ฐ ์ต๊ทผ์๋ Flask ์์ฒด์ built-in CLI ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค๊ณ ํ๋ค.
-
ํ๋ผ์คํฌ ๋ทฐ ํจ์๋ ์์ ํ ๋ ๋ฆฝ๋ ๋ ๊ฐ์ ๊ธฐ๋ฅ์ด ๋ง์น ํ๋์ ๊ธฐ๋ฅ์ฒ๋ผ ๋ณด์ด๋๋ฐ ์ด๋ ์ ์ง ๋ณด์์ ์ด๋ ค์์ ์ค ์ ์๋ค.
-
๋ทฐ ํจ์๋ ์ ํํ request์ ๋ํ response๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
-
์ผ๋ฐ์ ์ผ๋ก request๋ application์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ค
์ฌ์ฉ์๊ฐ ๊ณ์ ์ ์์ฑํ๋ค โ ์ฌ์ฉ์๊ฐ id์ pw๋ฅผ ์ ๋ ฅํ๊ณ ์ ์ก๋ฒํผ์ ๋๋ฅธ๋ค โ ์๋ฒ์์๋ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๋ ์ฌ์ฉ์์ request๋ฅผ ๋ฐ๋๋ค โ ํ๋ผ์คํฌ๋ request์ ๋ํ ๋์์ ์ฒ๋ฆฌํ๋ ๋ทฐ ํจ์์ ์ด request๋ฅผ dispatch ํ๋ค โ ๋ทฐ ํจ์๋ ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ์ฐ๊ฒฐํ์ฌ ์ฌ์ฉ์๋ฅผ ์ถ๊ฐํ๋ค. โ ๊ทธ์๋ํ ์๋ต์ ์ฌ์ฉ์์๊ฒ ๋ณด๋ธ๋ค.
- ์ด ๋ ๊ฐ์ง์ ํํ๋ฅผ ๋น์ง๋์ค ๋ก์ง ๊ณผ ํ๋ ์ ํ ์ด์ ๋ก์ง ์ผ๋ก ๋ถ๋ฅธ๋ค.
- ๋๊ฐ์ง ๋ก์ง์ด ์์ฌ ์์ผ๋ฉด ์ฝ๋์ ์ ์ง ๋ณด์๋ ์ด๋ ค์์ง๋ค.
-
ํ๋ ์ ํ ์ด์ ๋ก์ง์ ํ ํ๋ฆฟ ์ผ๋ก ์ด๋์ํค๋ ๊ฒ์ application ์ ์ง ๋ณด์์ ๋์์ ์ค๋ค.
-
ํ ํ๋ฆฟ์ ์๋ต ํ ์คํธ๋ฅผ ํฌํจํ๊ณ ์๋ ํ์ผ์ด๋ค.
-
ํ ํ๋ฆฟ์ request ๋ด์ฉ์์ ์ธ์ ๊ฐ๋ฅํ ๋์ ํํธ์ ๋ํ ๋ณ์๋ค์ ํฌํจํ๊ณ ์๋ค.
-
๋ณ์๋ค์ ์ค์ ๊ฐ์ผ๋ก ๋ฐ๊พธ๋ ํ๋ก์ธ์ค์ ์ต์ข ์๋ต ๋ฌธ์์ด์ ๋ฆฌํดํ๋ ํ๋ก์ธ์ค๋ฅผ ๋ ๋๋ง ์ด๋ผ๊ณ ํ๋ค
-
ํ ํ๋ฆฟ์ ๋ ๋๋งํ๋ ์์ ์ ์ํด Flask๋ Jinja2 ๋ผ๋ ๊ฐ๋ คํฌํ ํ ํ๋ฆฟ ์์ง์ ์ฌ์ฉํ๋ค
- Jinja2 Tamplate๋ response text๋ฅผ includeํ๋ file์ด๋ค.
- ๋ณดํต ํ๋ผ์คํฌ์์๋ application folder ์์ ์์นํ๋ tamplates ์๋ธํด๋์์ ํ ํ๋ฆฟ์ ๊ฒ์ํ๋ค.
- ํ๋ผ์คํฌ์์ Template์ rendering ํ๊ธฐ ์ํด์๋ render_template ํจ์๋ฅผ ์ฌ์ฉํ๋ค.
from flask import Flask, render_template
-
ํ ํ๋ฆฟ์์ ์ฌ์ฉ๋๋ {{name}} ์ ๋ณ์๋ฅผ ์๋งํ๋ค.
-
Jinja2 ๋ ์ด๋ค ํ์ ์ ๋ณ์๋ผ๋ ์ธ์ํ๋ค.
-
๋ณ์๋ filter๋ฅผ ์ฌ์ฉํด์ ์์ ํ ์ ์์ผ๋ฉฐ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค
Hello, {{name|capitalize}}
-
Jinja2๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๋ณ์๋ฅผ ๋ณด์ ๋ชฉ์ ์ผ๋ก ์ด์ค์ผ์ดํํ๋ค.
-
Jinja2๋ If๋ฌธ, for๋ฌธ, macro(like function)๋ฌธ ๋ฑ์ ํ ํ๋ฆฟ์์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋ค. ๋ฟ๋ง ์๋๋ผ import, include, ์์๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
- Bootstrap์ ํธ์ํฐ์์ ์ ๊ณตํ๋ ์คํ์์ค ํ๋ ์์ํฌ๋ค.
- Bootstrap์ ๋ชจ๋ ์น ๋ธ๋ผ์ฐ์ ์ ํธํ๋๋ ๊น๋ํ๊ณ ๋งค๋ ฅ์ ์ธ ์น ํ์ด์ง๋ฅผ ์์ฑํ ์ ์๋๋กํ๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค.
- Bootstrap์ client ์ธก์ ํ๋ ์์ํฌ๋ค.
- ์๋ฒ์์๋ ๋ถํธ์คํธ๋ฉ์ CSS์ JavaScript ํ์ผ์ ์ฐธ์กฐํ๋ HTML ์๋ต์ ์ ๊ณตํด์ผ ํ๋ค.
- ๋ํ ์๋ฒ๋ HTML, CSS, JavaScript ์ฝ๋๋ฅผ ํตํด์ ์ํ๋ ์ปดํฌ๋ํธ๋ค์ ์ธ์คํด์คํ ํ๋ค.
- ์ด๋ฐ ์์ ์์ ํ ํ๋ฆฟ์์ ์ด๋ฃจ์ด์ง๊ธฐ์ ์ ํฉํ๋ค.
- ๋ถํธ์คํธ๋ฉ๊ณผ APP์ ํตํฉํ๋ ๊ฐ์ฅ ํ์คํ ๋ฐฉ๋ฒ์ ํ์ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ๋ค์ ํ ํ๋ฆฟ์ ๋ง๋ค์ด ๋๋ ๊ฒ์ด๋ค.
- flask-bootstrap ์ ์ค์นํ์
- ํ๋ผ์คํฌ์ ํ์ฅ์ ๋ณดํต App instance๊ฐ ์์ฑ๋ ๋ ์ด๊ธฐํ๋๋ค.
import flask.ext
๋ ๋์ด์ ์ง์ํ์ง ์๋๋ค
- Flask-Bootstrap์ด ํ๋ฒ ์ด๊ธฐํ๋๋ฉด ๋ชจ๋ ๋ถํธ์คํธ๋ฉ ํ์ผ์ ํฌํจํ๋ ๋ฒ ์ด์ค ํ ํ๋ฆฟ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉํ ์ ์๋ค.
- Jinja2 extends ๋ ํ ํ๋ฆฟ ์์์ ๊ตฌํํ๋ค.
- Flask-Bootstrap์ ๋ฒ ์ด์ค ํ ํ๋ฆฟ์ ๋ชจ๋ ๋ถํธ์คํธ๋จ CSS, JavaScript๋ฅผ ํฌํจํ๋ ์ค์ผ๋ ํค ์น ํ์ด์ง๋ฅผ ์ ๊ณตํ๋ค.
- ๋ฒ ์ด์ค ํ ํ๋ฆฟ์ ํ์๋ ํ ํ๋ฆฟ์ด ์ค๋ฒ๋ผ์ด๋ํ ์ ์๋๋ก ๋ธ๋ก์ ์ ์ํ๋ค.
- ๋ธ๋ก์
{% block %}
and{% endblock %}
์ผ๋ก ์ ์ํ๋ค.
- ๋ด๋น๊ฒ์ด์ ๋ฐ์ ๊ฐ์ด ์๋ก ๋ค๋ฅธ ํ์ด์ง๋ค์ ์ฐ๊ฒฐํ๋ ๊ฒ์ ๋งํฌ๋ผ๊ณ ๋ถ๋ฅธ๋ค
- ๋์ ๋ผ์ฐํธ๋ฅผ ์ํด ํ ํ๋ฆฟ์์ URL์ ๊ตฌ์ฑํ๋ ๊ฒ์ ์์กด์ฑ์ด ๋ฐ์ํ๊ฑฐ๋ ๋ผ์ฐํธ ์ฌ๊ตฌ์ฑ์ผ๋ก ๋งํฌ๊ฐ ๊นจ์ง ์ ์๋ค.
- Flask๋
url_for()
ํฌํผ ํจ์๋ฅผ ์ ๊ณตํ๋ค. - ์ด ํจ์๋ URL ๋งต์ ์ ์ฅ๋ ์ ๋ณด๋ฅผ ์ด์ฉํ๋ค.
- ์ด ํจ์๋ ํ๋์ ๋ทฐ ํจ์ ์ด๋ฆ (ํน์ app.add_url_route( )์ ํจ๊ป ์ ์๋ ๋ผ์ฐํธ๋ฅผ ์ํ endpoint ์ด๋ฆ) ๊ฐ๊ณ URL์ ๋ฆฌํดํ๋ค.
- ์ฌ์ฉ๋ฒ์
href = {{ url_for('user', name= 'David') }}
- Flask๋ ๊ธฐ๋ณธ์ ์ผ๋ก application์ root ํด๋์ ์๋ static์ด๋ผ๊ณ ํ๋ ์๋ธ๋๋ ํ ๋ฆฌ์์ ์ ์ ํ์ผ์ ์ฐพ๋๋ค.
- ์น ์ดํ๋ฆฌ์ผ์ด์ ์์ ๋ ์ง์ ์๊ฐ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ์ฌ์ฉ์๊ฐ ์ ์ธ๊ณ์์ ๋ค๋ฅธ ์๊ฐ๋๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ ๋ฌธ์ ๊ฐ ์๋๋ค.
- ์๋ฒ๋ UTC๋ฅผ ์ฌ์ฉํ๊ณ ์น ๋ธ๋ผ์ฐ์ ๋ ์ ์ก๋ฐ์ ์๊ฐ ์ ๋์ ์์ ์ ๋ก์ปฌ ์๊ฐ์ผ๋ก ๋ณ๊ฒฝํ๊ณ ๋ ๋๋งํ๋ค.
- Flask-WTF ํ์ฅ์ ์น ํผ์ ์ฌ์ฉํ์ฌ ํจ์ฌ ๋ฉ์ง ๊ฒฝํ์ ํ๋๋ก ๋์์ค๋ค
-
Flask-WTF๋ ํฌ๋ก์ค ์ฌ์ดํธ ๋ฆฌํ์คํธ ์์กฐ (CSRF) ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ๋ชจ๋ ํผ์ ๋ณดํธํ๋ค.
-
CSRF ๊ณต๊ฒฉ์ ์ ์์ ์น์ฌ์ดํธ์์ ํฌ์์๊ฐ ๋ก๊ทธ์ธํ ๋ค๋ฅธ ์น์ฌ์ดํธ๋ก ๋ฆฌํ์คํธ๋ฅผ ์ ์กํ ๋ ์ผ์ด๋๋ค.
-
CSRF ๋ณดํธ๋ฅผ ์ํด Flask-WTF๋ ์ํธํ ํค๋ฅผ ์ค์ ํ๊ธฐ ์ํ app์ด ํ์ํ๋ค.
-
Flask-WTF๋ ์ด ํค๋ฅผ ์ฌ์ฉํ์ฌ ์ํธํ๋ ํ ํฐ์ ์์ฑํ๊ณ ์ด ํ ํฐ์ ํผ ๋ฐ์ดํฐ์ ํจ๊ป ๋ฆฌํ์คํธ๋ฅผ ์ธ์ฆํ๋ค.
-
์ํธ ์ค์ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค
app = Flask(__name__) app.config['SECRET_KEY'] = 'secret key'
-
app.config
๋ ์ค์ ๋ฉด์๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ณต๊ฐ์ด๋ค. -
๋ณด์์ฑ ํฅ์์ ์ํด ๋ณด์ ํค๋ ํ๊ฒฝ๋ณ์์ ์ ์ฅํ๋ค.
- Flask-WTF์ Form ํด๋์ค๋ก๋ถํฐ ์์ํ ํด๋์ค์ ์ํด ํํ๋๋ค.
- ๊ฐ ํ๋์ ์ค๋ธ์ ํธ๋ ํ๋ ์ด์์ ๊ฒ์ฆ์๊ฐ ๋ถ์ด ์๋ค. ๊ฒ์ฆ์๋ ์ฌ์ฉ์์ ์ ๋ ฅ๊ฐ์ด ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ๋ค.
- WTFrom์์๋ HTML ํ๋๋ฅผ ์ ๊ฒ์ฆ์๋ฅผ ์ง์ํ๋ค.
- HTML ํ๋๋ ํ ์คํธ ํ๋, ํจ์ค์๋ ํ๋, True or False๊ฐ ํ๋ ๋ฑ๋ฑ์ด ์๋ค.
- ๊ฒ์ฆ์๋ ์ด๋ฉ์ผ ์ฃผ์๊ฒ์ฆ, IPv4 ๊ฒ์ฆ, ์ ๋ ฅ๊ฐ ๋ฌธ์์ด ๊ธธ์ด ๊ฒ์ฆ ๋ฑ๋ฑ์ด ์๋ค.
-
ํผ ํ๋๋ ํธ์ถ์ด ๊ฐ๋ฅํ๋ค.
-
ํผ ํ๋๊ฐ ํธ์ถ๋๋ฉด ํ ํ๋ฆฟ์ HTML๋ก ๋๋๋ง ๋๋ค.
-
Flask-Bootstrap์ ์ ์ฒด Flask-WTF ํผ์ ๋๋๋งํ๊ธฐ ์ํด ๋ถํธ์คํธ๋ฉ์ ๋ฏธ๋ฆฌ ์ ์๋ ํผ ์คํ์ผ์ ์ฌ์ฉํ ์ ์๊ฒ ํฌํผ ํจ์๋ฅผ ์ ๊ณตํ๋๋ฐ ํ ๋ฒ์ ํธ์ถ๋ก ์ด๋ฃจ์ด์ง๊ณ ์ด์ ํผ์ด ๋๋๋ง ๋๋ค.
{% import "bootstrap/wtf.html" as wtf %} {{ wtf.quick_form(form) }}
app.route
๋ฐ์ฝ๋ ์ดํฐ์ ์ถ๊ฐ๋methods
์ธ์๋ ํ๋ผ์คํฌ์์ URL ๋งต์ GET๊ณผ POST ๋ฆฌํ์คํธ๋ฅผ ์ํ ํธ๋ค๋ฌ๋ก ๋ทฐ ํจ์๋ฅผ ๋ฑ๋กํ๋๋ก ํ๋ค.- ์๋ธ๋ฏธ์ ์ ๋๋๋ก์ด๋ฉด POST ๋ฆฌํ์คํธ๋ก ์ฒ๋ฆฌํ๋ค. GET์์๋ ํ ์ ์์ง๋ง ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ URL์ ํฌํจ๋์ด ๋ ์๊ฐ์ ๋ณด์์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
- POST ๋ฐฉ์์ผ๋ก ์์ฒญํ๊ณ ์ ์๋ก๊ณ ์นจ์ ๋๋ ์๋ ์ข ์ข ์ผ์ด๋๋ ๋ฐ์์ด๋ค. ์ฆ, ์๋ก๊ณ ์นจ์ ํผ ์๋ธ๋ฏธ์ ์ ๋ ๋ฒ ํ๊ฒ๋๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํจ๋ค.
- ๋ฐ๋ผ์ ์น app์ด ๋ธ๋ผ์ฐ์ ์ ์ํด ์ ์ก๋ ๋ง์ง๋ง ์์ฒญ์ผ๋ก POST ์์ฒญ์ ๋จ๊ธฐ์ง ์๋ ๊ฒ์ด ์ข์ ์ต๊ด์ด๋ค.
- ์ด ์ต๊ด์ ์ ์์ ์ธ ์๋ต ๋์ ์ ๋ฆฌ๋ค์ด๋ ํธ์ ํจ๊ป POST ์์ฒญ์ ๋ํด ์๋ตํ๋ ๊ฒ์ด๋ค. ์ด๋ฅผ Post/Redirect/Get pattern ์ด๋ค.
- ํฉ๋ฆฌ์ ์ด๊ณ ์ ๋นํ ์ผ๋ค์ ์ธ๋ดํ๊ณ ๋ถํฉ๋ฆฌํ๊ณ ๋ถ์ํ ์ผ์ ์ฐธ์ง ์๋ ๊ฒ์ด ๋ฐ๋ฅด๊ฒ ์ธ์์ ์ฌ๋ ๋ฐฉ๋ฒ์ด๋ค.
- ์ ๋ฐฉ๋ฒ์๋ ๋ฌธ์ ์ ์ด ์๋ค. ๋ฆฌ๋ค์ด๋ ์ ํ๋ ์๊ฐ Form data๋ ์ฌ๋ผ์ง๋ค. ๋ฐ๋ผ์ app์ ์ฌ์ฉ์์ Form data๋ฅผ ์ ์ฅํด๋์ด์ผ ํ๋ค.
- app์ ์ฌ์ฉ์ ์ธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ฌ ์ฌ์ฉ์์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ์ตํด๋ธ๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ์ ์ธ์ ์ ํด๋ผ์ด์ธํธ ์ธก ์ฟ ํค์ ์ ์ฅ๋๋ค. ์ด๋ ์ค์ ๋์ด ์๋ SECRET_KEY๋ก ์ํธํ๋์ด ์๋ค. ์ฟ ํค์ ์ฝํ ์ธ ๊ฐ ์กฐ์๋๋ฉด ์๋ช ์ด ๋ฌดํจํ๋๊ณ ๊ฒฐ๊ตญ ์ธ์ ์์ฒด๊ฐ ๋ฌดํจํ๋๋ค.
- ์ธ์ ์ ์ฌ์ฉํ๋ฉด ๋ก์ปฌ ๋ณ์์๋ name์ session['name'] ์ผ๋ก ์ ์ฅ๋์๊ณ ์ดํ ๋ฆฌํ์คํธ์์๋ ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
- Structured Query Language
- ๊ด๊ณํ ๋ชจ๋ธ์ด๋ผ๊ณ ํ๋ค.
- ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค.
- Column์ ์๋ ํ ์ด๋ธ๋ง๋ค ๊ณ ์ ๋์ด ์๋ค.
- Row ์๋ ๋์ด๋๋ค.
- ๊ธฐ๋ณธํค(primary key)์ ์ธ๋ํค(foreign key)๋ฅผ ์ค์ ํ ์ ์๋ค.
- ๊ธฐ๋ณธํค๋ ํด๋น ํ์ ์๋ณ์์ด๊ณ ์ธ๋ํค๋ ์ด๋ฅผ ์ฐธ์กฐํ๋ค.
- ํ ์ด๋ธ ๋์ ์ปฌ๋์ (collection)
- ๋ ์ฝ๋ ๋์ ๋ํ๋จผํธ(document) ๋ฅผ ์ฌ์ฉํ๋ค.
- ์ญ์ ๊ทํ(denormalization)๋ผ๊ณ ํ๋ ์คํผ๋ ์ด์ ์ ์ฌ์ฉํ๋ฉฐ ๋ฐ์ดํฐ ์ค๋ณต์ ๋ฐฉ์งํ๋ค.
- ๊ฐ์ฒด์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ์๋์ผ๋ก ๋งคํ(์ฐ๊ฒฐ)ํด์ฃผ๋ ๊ฒ์ ๋งํ๋ค.
- ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ณ , ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ํ ์ด๋ธ์ ์ฌ์ฉํ๋ค.
- ๊ฐ์ฒด ๋ชจ๋ธ๊ณผ ๊ด๊ณํ ๋ชจ๋ธ ๊ฐ์ ๋ถ์ผ์น๊ฐ ์กด์ฌํ๋ค.
- ORM์ ํตํด ๊ฐ์ฒด ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ฐํ์ผ๋ก SQL์ ์๋์ผ๋ก ์์ฑํ์ฌ ๋ถ์ผ์น๋ฅผ ํด๊ฒฐํ๋ค.
-
Flask-Mail์ SMTP (Simple Mail Tranfer Protocol) ์๋ฒ์ ์ฐ๊ฒฐํ์ฌ ์ด๋ฉ์ผ์ ์๋ฒ์ ์ ๋ฌํจ์ผ๋ก ์ด๋ฉ์ผ์ ๋ฐ์กํ๋ค.
-
๋ค๋ฅธ ์ค์ ์ด ์๋ค๋ฉด Flask-Mail์ ํฌํธ 25๋ฒ์ ํตํด localhost ์ ์ฐ๊ฒฐํ๋ค.
-
์ด๋๋ ์ธ์ฆ์์ด ์ด๋ฉ์ผ์ ๋ฐ์กํ๋ค.
-
์ธ๋ถ SMTP ์๋ฒ๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ๋ ํธํ ์ ์๋ค. -> google์ smtp๋ฅผ ์ด์ฉํ๋ค
-
์ธ๋ถ SMTP ์๋ฒ๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ๋ ํธํ ์ ์๋ค.
-
๋ค์์ ๊ตฌ๊ธ์ Gmail ๊ณ์ ์ ํตํด ์ด๋ฉ์ผ์ ์ ์กํ๋ ๋ฐฉ๋ฒ์ด๋ค.
app.config['MAIL_SERVER'] = 'smtp.googlemail.com' app.config['MAIL_PORT'] = 587 app.config['MAIL_USE_TLS'] = True app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
-
๊ฐ์ธ์ ๋ณด๋ ์ ๋๋ก ์คํฌ๋ฆฝํธ์ ์ ๋ ฅํ์ง ๋ง๊ณ ์์ ๊ฐ์ด ํ๊ฒฝ๋ณ์๋ก ์ฌ์ฉํด์ผ ํ๋ค.
-
ํ๊ฒฝ๋ณ์๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค
export MAIL_USERNAME=๊ตฌ๊ธ์์ด๋ export MAIL_PASSWORD=๋น๋ฐ๋ฒํธ
โ ๏ธ ๋ง์ฝ ์ค์ต์ ์ฌ์ฉํ๋ ๊ตฌ๊ธ์์ด๋๊ฐ 2-step ์ธ์ฆ์ด๋ผ๋ฉดsmtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8 [https://support.google.com/mail/?p=BadCredentials](https://support.google.com/mail/?p=BadCredentials)
์ด๋ผ๋ Error๊ฐ ๋ฐ ๊ฒ์ด๋ค. ๊ทธ๋๋ Google Account์ Less secure app access ์์Allow Less Security App
์On
์ผ๋ก ์ค์ ํด์ฃผ์ด์ผ ํ๋ค.
-
- ์ด๋ฉ์ผ ์ ์ก ๊ธฐ๋ฅ์ ํจ์๋ก ์ถ์ํ ํ๋ ๊ฒ์ ์ถ์ฒํ๋ค.
- ์ด ํจ์๋ Jinja2 ํ
ํ๋ฆฟ์ผ๋ก ์ด๋ฉ์ผ ๋ณธ๋ฌธ์ ๋ ๋๋งํ๋ค.
- code์์๋ ์ด๋ฉ์ผ ํ ํ๋ฆฟ์ mail directory์ ๋ชจ์๋์์์ ์ ์ ์๋ค.
Book-Flask-web-develop/email.py at main ยท DavidKimDY/Book-Flask-web-develop
- ์์ ์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด mail์ ๋ณด๋ด๋ ๋์ web browser๊ฐ ๋ฉ์ถ๋ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
- ๋ฆฌํ์คํธ ํธ๋ค๋ง์ ํ๋ ๋์ ๋ถํ์ํ ์ง์ฐ์ ํผํ๊ธฐ ์ํด, ์ด๋ฉ์ผ ์ ์ก ํจ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋๋ก ์ฒ๋ฆฌํ๋ค.
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(to, subject, template, **kwargs):
msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
msg.body = render_template(template + '.txt', **kwargs)
msg.html = render_template(template + '.html', **kwargs)
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
return thr
- ๋ง์ ํ๋ผ์คํฌ ํ์ฅ์ ํ์ฑํ๋ ์ดํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ฆฌํ์คํธ ์ปจํ ์คํธ๊ฐ ์๋ค๋ ๊ฐ์ ํ์ ๋์ํ๋ค.
- Flask-Mail์ send() ํจ์์์ current_app์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๊ฐ ํ์ฑํ๋ ๊ฒ์ ์๊ตฌํ๋ค. ํ์ง๋ง send() ํจ์๊ฐ ๋ค๋ฅธ ์ค๋ ๋์์ ์คํ๋๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๊ฐ ์ธ์์ ์ผ๋ก app.app_context()๋ฅผ ์์ฑํด์ผ ํ๋ค.
- ๋์ฉ๋ ์ด๋ฉ์ผ ์ ์ก ์์ ๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์๋ ์ด๋ฉ์ผ ์ ์ก์ ํ๋์ ์์ ์ผ๋ก ๋ง๋๋ ๊ฒ์ด ์ด๋ฉ์ผ์ ์ ์กํ ๋๋ง๋ค ์๋ก์ด ์ค๋ ๋๋ฅผ ์์ํ๋ ๊ฒ๋ณด๋ค ๋ ๋ซ๋ค.
- ์๋ฅผ ๋ค๋ฉด send_async_email() ํจ์์ ์คํ์ Celery ํ์คํฌ ํ์ ์ ์กํ๋ ๊ฒ์ด๋ค.
- ์ดํ๋ฆฌ์ผ์ด์ ์ด ์ปค์ง์๋ก ํ๋์ ์คํฌ๋ฆฝํธ ์์ค ํ์ผ์์ ์์ ํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ค.
- ๋๋ฅธ ํ๋ ์์ํฌ์ ๋ฌ๋ฆฌ ํ๋ผ์คํฌ๋ ํน์ ๊ตฌ์กฐ๋ฅผ ์๊ตฌํ์ง ์๋๋ค.
- ๋ฐ๋ผ์ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒ์ ๊ฐ๋ฐ์์ ๋ชซ์ด๋ค.
flasky/
โโโ LICENSE
โโโ README.md
โโโ app
โย ย โโโ __init__.py
โย ย โโโ email.py
โย ย โโโ main
โย ย โย ย โโโ __init__.py
โย ย โย ย โโโ errors.py
โย ย โย ย โโโ forms.py
โย ย โย ย โโโ views.py
โย ย โโโ models.py
โย ย โโโ static
โย ย โย ย โโโ favicon.ico
โย ย โโโ templates
โย ย โโโ 404.html
โย ย โโโ 500.html
โย ย โโโ base.html
โย ย โโโ index.html
โย ย โโโ mail
โย ย โโโ new_user.html
โย ย โโโ new_user.txt
โโโ config.py
โโโ flasky.py
โโโ migrations
โย ย โโโ README
โย ย โโโ alembic.ini
โย ย โโโ env.py
โย ย โโโ script.py.mako
โย ย โโโ versions
โย ย โโโ 38c4e85512a9_initial_migration.py
โโโ requirements.txt
โโโ tests
โโโ __init__.py
โโโ test_basics.py
- ์ดํ๋ฆฌ์ผ์ด์ ์ ์ข ์ข ์ฌ๋ฌ ์ค์ ๊ฐ์ด ํ์ํ๋ค.
- ๊ฐ๋ฐ, ํ ์คํธ, ์ ํํ ๊ณผ์ ์ค์ ์๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ํ์ ์ด๋ค.
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
MAIL_SERVER = os.environ.get('MAIL_SERVER', 'smtp.googlemail.com')
MAIL_PORT = int(os.environ.get('MAIL_PORT', '587'))
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in \
['true', 'on', '1']
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>'
FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')
SQLALCHEMY_TRACK_MODIFICATIONS = False
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
'sqlite://'
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
- Config class๋ ๋ชจ๋ ์ค์ ์ ์ฌ์ฉ๋๋ ๊ณตํต๊ฐ๋ค์ ํฌํจํ๊ณ ์๋ค.
- ์ข ๋ ํธํ์ฑ์๊ณ ์์ ํ ์ค์ ์ ํ๋ ค๋ฉด ํ๊ฒฝ ๋ณ์์์ ์ต์
์ผ๋ก ์ํฌํธํด์ผ ํ๋ค.
- ์๋ฅผ ๋ค๋ฉด
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
- ์๋ฅผ ๋ค๋ฉด
SQLALCHEMY_DATABASE_URI
๋ณ์๋ ๊ฐ ์ค์ ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ค์ ๋์ด ์๋ค. ์๋ก ๋ค๋ฅธ DB ํ๊ฒฝ์์ ๋์ํ ์ ์๊ฒ ํด์ค๋ค.init_app()
ํด๋์ค ๋ฉ์๋๋ ์ค์ ์ ๋ฐ๋ฅธ ์ด๊ธฐํ ์์ ์ ์ํํด์ค๋ค.
app
โโโ __init__.py
โโโ email.py
โโโ main
โย ย โโโ __init__.py
โย ย โโโ errors.py
โย ย โโโ forms.py
โย ย โโโ views.py
โโโ models.py
โโโ static
โย ย โโโ favicon.ico
โโโ templates
โโโ 404.html
โโโ 500.html
โโโ base.html
โโโ index.html
โโโ mail
โโโ new_user.html
โโโ new_user.txt
- app ํจํค์ง์๋ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฝ๋, ํ ํ๋ฆฟ, ์ ์ ํ์ผ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ, ์ด๋ฉ์ผ ์์ ์ฝ๋ ๋ฑ์ด ์กด์ฌํ๋ค.
๋ธ๋ฃจํ๋ฆฐํธ๋ฅผ ๊ฐ์ง ๋ชจ๋ํ๋ ์ดํ๋ฆฌ์ผ์ด์ - Flask 0.11-dev documentation
- ๋๊ท๋ชจ ์ดํ๋ฆฌ์ผ์ด์ ๊ตฌ์กฐ๋ฅผ ์ง์ํ๊ธฐ ์ํ Flask์ ๊ธฐ๋ฅ
- ๋ธ๋ฃจํ๋ฆฐํธ๋ ๋ํ ์ดํ๋ฆฌ์ผ์ด์ ์ด ๋์ํ๋ ๋ฐฉ์์ ๋จ์ํํ๋ค
- ๋ธ๋ฃจํ๋ฆฐํธ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ธ๋ฃจํ๋ฆฐํธ์ด ๋ฑ๋ก๋ ๋ ์คํํ ๋์์ ๊ธฐ๋กํ๋ค๋ ๊ฒ์ด๋ค.
- ํ๋ผ์คํฌ๋ ์์ฒญ์ ๋ณด๋ด๊ณ ํ๋์ ๋์ ์์ ๋ค๋ฅธ ๊ณณ์ผ๋ก URL์ ์์ฑํ ๋ ๋ทฐ ํจ์์ ๋ธ๋ฃจํ๋ฆฐํธ์ ์ฐ๊ด์ ๋งบ๋๋ค.
- ์ผ๋ฐ์ ์ธ ํจํด์ ์ฒญ์ฌ์ง์ ์ํฌํธํ ๋ ์ดํ๋ฆฌ์ผ์ด์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
- ํ์ง๋ง ์ด ๊ฐ์ฒด์ ์์ฑ์ ํจ์๋ก ์ฎ๊ธด๋ค๋ฉด, ๋์ค์ ์ด ๊ฐ์ฒด์ ๋ํ ๋ณต์ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์๋ค.
-
ํจ์ค์๋๋ฅผ ์ ์ฅํ ๋๋ ํด์ฑ(hashing)์ ์ฌ์ฉํ๋ค
-
์ฆ, ํจ์ค์๋๋ฅผ ์๋ ๊ทธ๋๋ DB์ ์ ์ฅํ๋ ๊ฒ์ด์๋ ํด์ฑ์ ํตํด ๋ณํ๋ ๋ฌธ์์ด์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ด๋ค.
-
์๋ฅผ ๋ค์ด๋ณด์.
Password : "applebanana" โ [Hash function] โ DB : "AE21-00FF-E112"
[๋ก๊ทธ์ธ ๊ณผ์ ]
- ์ฌ์ฉ์๊ฐ "applebanana"๋ก password๋ฅผ ์ ๋ ฅ
- hash function์ ํตํด์ ๋ณํ๋ ๊ฐ์ ํ๋
- ๋ณํ๋ ๊ฐ์ ๊ฐ์ง๊ณ DB์ ์ ์ฅ๋ ๊ฐ๊ณผ ๋น๊ต
[๋ณด์์ฑ]
- "applebanana" โ hash โ "AE21-00FF-E112" (Possible)
- "AE21-00FF-E112" โ hash โ "applebanana" (Impossible)
- ์ฆ, ๋ณํ๋ ๊ฐ์ ๊ฐ์ง๊ณ ๋ณํ๋๊ธฐ ์ ๊ฐ์ ์ฐพ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค.
-
Werkzeug [์์ ] ์ WSGI web application library์ด๋ค.
-
์์ ์ ๋ณด์ ๋ชจ๋์ ์ฌ์ฉํ๋ฉด ๋ณด์ ํจ์ค์๋ ํด์ฑ์ ํธํ๊ฒ ๊ตฌํํ ์ ์๋ค.
generate_password_hash(password, method=pbkdf2:sha1, salt_lenth=8)
โ ์ด ํจ์๋ plain-text์ธ password๋ฅผ ๋ฐ์์ password hash๋ฅผ returnํ๋ค.
โ method, length๋ ๊ทธ๋๋ก ๋๊ณ ์ฌ์ฉํด๋ ๋๋ค.
check_password_hash(hash, password)
โ DB์์ ์ถ์ถํ password hash ์ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ password๋ฅผ ๋น๊ตํ๋ค.
โ True๊ฐ ๋ฐํ๋๋ฉด ํจ์ค์๋๊ฐ ์ผ์นํ๋ค๋ ๋ป์ด๋ค.
- ์ฌ์ฉ์ ์ธ์ฆ๊ณผ ๊ด๋ จ๋ ๋ผ์ฐํธ๋ auth ๋ธ๋ฃจํ๋ฆฐํธ์ ์ถ๊ฐํ ์ ์๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ๊ธฐ๋ฅ์ ๋ค๋ฅธ ์งํฉ์ ์ํด ๋ค๋ฅธ ๋ธ๋ฃจํ๋ฆฐํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ฝ๋๋ฅผ ๊ตฌ์กฐ์ ์ผ๋ก ๋ณด๊ธฐ ์ข๊ฒ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด๋ค.
-
๊ฐ์ ์ด๋ฆ์ ํจํค์ง์์ ํธ์คํธํ๋ค.
app/auth/__init__.py
์์ auth ๋ธ๋ฃจํ๋ฆฐํธ๋ฅผ ์์ฑํ๋คfrom flask import Blueprint auth = Blueprint('auth', __name__) from . import views
-
views.py ์์ auth๋ฅผ ํธ์ถํ๋ค.
app/auth/views.py
from flask import render_template from . import auth @auth.route('/login') def login(): return render_template('auth/login.html')
์ธ๋ป๋ณด๋ฉด ์ํ ๊ตฌ์กฐ์ฒ๋ผ ๋ณด์ด์ง๋ง
__init__.py
๋auth
ํจํค์ง๊ฐ ์ํฌํธ ๋ ๋ ํ๋ฒ ์คํ๋๋ค.๊ทธ๋ฆฌ๊ณ
[views.py](http://views.py)
๊ฐ ์คํ๋๋ฉด์__init__.py
์์ ์ ์ธํ auth blueprint๋ฅผ ๋ถ๋ฌ์์ ์ฌ์ฉํ๋ค.render_template('auth/login.html')
์์ ๊ดํธ ์์ ๊ฒฝ๋ก๋app/templates/auth/login.html
์ด๋ค.render_tamplate()
ํจ์๋ ๋จผ์ ์ดํ๋ฆฌ์ผ์ด์ ์ฉ์ผ๋ก ์ค์ ๋ ํ ํ๋ฆฟ ํ๋๋ฅผ ์ฐ์ ๊ฒ์ํ๋ค. -
๋ธ๋ฃจํ๋ฆฐํธ๋ฅผ ๋ถ์ฐฉํ๋ค.
app/__inti__.py
def create_app(config_name): # ... from .auth import auth as auth_blueprint app.register_blueprint(auth_blueprint, url_prefix='/auth') return app
url_prefix
์ธ์๋ ์ต์ ์ด๋ค.url_prefix
์ธ์ ์ต์ ์ ์ฌ์ฉํ๋ฉด ํด๋น ๋ธ๋ฃจํ๋ฆฐํธ์ ์ ์๋ ๋ชจ๋ ๋ผ์ฐํธ๋ ์ฃผ์ด์ง ์ ๋์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ฑ๋ก๋๋ค- ๋ฐ๋ผ์
/login
๋ผ์ฐํธ๋/auth/login
๋ก ๋ฑ๋ก๋์๊ณ http://localhost:500/auth/login ์์ ์ ์์ด ๊ฐ๋ฅํด ์ง๋ค.