blog.miguelgrinberg.com
ãã²ã«ã»ã°ãªã³ããŒã°
<<<å æ¬¡>>>
ãã®èšäºã¯ããã²ã«ã»ã°ãªãŒã³ããŒã°ã«ããæç§æžã®æ°çã®ç¬¬7éšã®ç¿»èš³ã§ãããèè
ã¯ãã®åºçç©ã2018幎5æã«å®æãããäºå®ã§ãã
ç§ã®åŽã§ã¯ã翻蚳ã«ã€ããŠããã€ããã§ãã
ããã¯ãFlask Mega-Tutorialã·ãªãŒãºã®ç¬¬7ç« ã§ãFlaskã¢ããªã±ãŒã·ã§ã³ã§ãšã©ãŒåŠçãåŠçããæ¹æ³ã説æããŸãã
åèãŸã§ã«ã以äžã¯ãã®ã·ãªãŒãºã®èšäºã®ãªã¹ãã§ãã
泚1ïŒãã®ã³ãŒã¹ã®å€ãããŒãžã§ã³ããæ¢ãã®å Žåã¯ããã¡ããã芧ãã ãã ã
泚2ïŒçªç¶ããã®ããã°ã®ç§ã®ïŒãã²ã«ïŒã®ä»äºãæ¯æããŠå£°ãäžãããå ŽåããŸãã¯åã«èšäºã1é±éåŸ
ã€å¿èããªãå Žåãç§ïŒãã²ã«ã°ãªãŒã³ããŒã°ïŒã¯ãã®ã¬ã€ãã®å®å
šçã«ããã±ãŒãžåãããé»åæžç±ãŸãã¯ãããªãæäŸããŸãã 詳现ã«ã€ããŠã¯ã learn.miguelgrinberg.comãã芧ãã ãã ã
ãã®ç« ã§ã¯ãæ°ãã颿°ã®ã³ãŒãã£ã³ã°ãã埮çç©åŠçã¢ããªã±ãŒã·ã§ã³ã«ç§»ãã代ããã«ããœãããŠã§ã¢ãããžã§ã¯ãã§åžžã«çºçãããšã©ãŒã«å¯ŸåŠããããã®ããã€ãã®æŠç¥ã«ã€ããŠèª¬æããŸãã ãã®ãããã¯ã説æããããã«ã 第6ç« ã§è¿œå ããã³ãŒããæå³çã«èª€ããŸããã èªã¿ç¶ããåã«ãèŠã€ãããããã©ããã確èªããŠãã ããïŒ
ãã®ç« ã®GitHubãªã³ã¯ïŒ Browse ã Zip ã Diff ã
Flaskã§ã®ãšã©ãŒåŠç
Flaskã¢ããªã±ãŒã·ã§ã³ã§ãšã©ãŒãçºçãããšã©ããªããŸããïŒ èŠã€ããããã®æè¯ã®æ¹æ³ã¯ãèªåã§ãããäœéšããããšã§ãã ã¢ããªã±ãŒã·ã§ã³ãèµ·åããå°ãªããšã2人ã®ãŠãŒã¶ãŒãç»é²ãããŠããããšã確èªããŠãã ããã ãŠãŒã¶ãŒã®1人ãšããŠãã°ã€ã³ãããããã¡ã€ã«ããŒãžãéããŠ[ç·šé]ãªã³ã¯ãã¯ãªãã¯ããŸãã ãããã¡ã€ã«ãšãã£ã¿ãŒã§ããŠãŒã¶ãŒåãæ¢ã«ç»é²ãããŠããå¥ã®ãŠãŒã¶ãŒã®æ¢åã®ååã«å€æŽããä¿®æ£ãé©çšããŠã¿ãŠãã ããã ããã«ããããå
éšãµãŒããŒãšã©ãŒããšããæãããããŒãžã衚瀺ãããŸãã

ã¢ããªã±ãŒã·ã§ã³ãå®è¡ãããŠããã¿ãŒããã«ã»ãã·ã§ã³ã§ããšã©ãŒã¹ã¿ãã¯ã®ãã¬ãŒã¹ã衚瀺ãããŸãã ã¹ã¿ãã¯ãã¬ãŒã¹ã¯ããšã©ãŒã®åå ãšãªã£ãè¡ã«è³ããŸã§ããã®ã¹ã¿ãã¯äžã®äžé£ã®åŒã³åºãã衚瀺ããããããšã©ãŒã®ãããã°æã«éåžžã«åœ¹ç«ã¡ãŸãã
(venv) $ flask run * Serving Flask app "microblog" * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) [2017-09-14 22:40:02,027] ERROR in app: Exception on /edit_profile [POST] Traceback (most recent call last): File "/home/miguel/microblog/venv/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context context) File "/home/miguel/microblog/venv/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 470, in do_execute cursor.execute(statement, parameters) sqlite3.IntegrityError: UNIQUE constraint failed: user.username
ã¹ã¿ãã¯ãã¬ãŒã¹ã¯ããšã©ãŒã®åå ã瀺ããŸãã ã¢ããªã±ãŒã·ã§ã³ã¯ããŠãŒã¶ãŒãæ°ãããŠãŒã¶ãŒåãæ¢ã«ã·ã¹ãã ã«ããå¥ã®ãŠãŒã¶ãŒãšäžèŽããªãããšã確èªããã«ãŠãŒã¶ãŒåã倿Žããããšãèš±å¯ããŸãã ãã®ãšã©ãŒã¯ãæ°ãããŠãŒã¶ãŒåãããŒã¿ããŒã¹ã«æžã蟌ãããšããSQLAlchemyããçºçããŸããããŠãŒã¶ãŒååãunique = Trueã§å®çŸ©ãããŠãããããããŒã¿ããŒã¹ã¯ãããæåŠããŸãã
ãŠãŒã¶ãŒã«è¡šç€ºããããšã©ãŒããŒãžã«ãšã©ãŒã«é¢ããå€ãã®æ
å ±ãå«ãŸããŠããªãããšãéèŠã§ãããããã¯æ£ããã§ãã ç§ã¯ééããªããäºæ
ãããŒã¿ããŒã¹ãšã©ãŒãŸãã¯ç§ã䜿çšããŠããããŒã¿ããŒã¹ãããã³ããŒã¿ããŒã¹å
ã®ããŒãã«ãšãã£ãŒã«ãã®ååãåå ã§ããããšããŠãŒã¶ãŒã«ç¥ãããããããŸããã ãã®æ
å ±ã¯ãã¹ãŠå
éšã®ãã®ã§ãªããã°ãªããŸããã
çæ³ãšã¯ã»ã©é ããã®ãããã€ããããŸãã pageããšã©ãŒããããã¢ããªã±ãŒã·ã§ã³ã®ã¬ã€ã¢ãŠããšäžèŽããªãããŒãžããããŸãã ãŸããã¿ãŒããã«ã«ãã³ããããéèŠãªã¢ããªã±ãŒã·ã§ã³ã¹ã¿ãã¯ãã¬ãŒã¹ãããããšã©ãŒãèŠéããªãããã«åžžã«ç¢ºèªããå¿
èŠããããŸãã ãããŠãã¡ããééãããããŸãã ããããã¹ãŠã®åé¡ã解決ããŸãããæåã«Flaskãããã°ã¢ãŒãã«ã€ããŠèª¬æããŸãããã
ãããã°ã¢ãŒã
äžèšã®ãšã©ãŒã®åŠçæ¹æ³ã¯ãéçšãµãŒããŒã§å®è¡ãããã·ã¹ãã ã«æé©ã§ãã ãšã©ãŒãããå ŽåããŠãŒã¶ãŒã«ã¯æªå®çŸ©ã®ãšã©ãŒã®ããŒãžã衚瀺ãããŸããïŒãã®ãšã©ãŒããŒãžããã£ãšæ¥œããããã€ããã§ãïŒãéèŠãªãšã©ãŒããŒã¿ã¯ãµãŒããŒåºåãŸãã¯ãã°ãã¡ã€ã«ã«ãããŸãã
ãã ããã¢ããªã±ãŒã·ã§ã³ãéçºããŠãããšãã¯ããããã°ã¢ãŒãããªã³ã«ããããšãã§ããŸãããããã°ã¢ãŒãã¯ãFlaskããã©ãŠã¶ã«çŽæ¥éåžžã«åªãããããã¬ã衚瀺ããã¢ãŒãã§ãã ãããã°ã¢ãŒããã¢ã¯ãã£ãã«ããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã忢ããæ¬¡ã®ç°å¢å€æ°ãèšå®ããŸãã
(venv) $ export FLASK_DEBUG=1
Microsoft Windowsãå®è¡ããŠããå Žåã¯ããšã¯ã¹ããŒãã®ä»£ããã«set
ã䜿çšããŠãã ããã
FLASK_DEBUGãèšå®ãããããµãŒããŒãåèµ·åããŸãã 端æ«ã®è¡ã¯ãèŠæ
£ãããã®ãšã¯å°ãç°ãªããŸãã
(venv) microblog2 $ flask run * Serving Flask app "microblog" * Forcing debug mode on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 177-562-960
次ã«ãã¢ããªã±ãŒã·ã§ã³ãå床ã¯ã©ãã·ã¥ãããŠããã©ãŠã¶ã§å¯Ÿè©±åãããã¬ãŒã確èªããŸãã

ãããã¬ãŒã䜿çšãããšãã¹ã¿ãã¯ã®åã¬ãã«ãå±éãã察å¿ãããœãŒã¹ã³ãŒãã衚瀺ã§ããŸãã ãŸããä»»æã®ãã¬ãŒã ã§Pythonãéããæå¹ãªPythonåŒãå®è¡ããŠã倿°ã®å€ã確èªããããšãã§ããŸãã
æ¬çªãµãŒããŒã§ã¯ãFlaskã¢ããªã±ãŒã·ã§ã³ããããã°ã¢ãŒãã§å®è¡ããªãã§ãã ããã ãããã¬ãŒã䜿çšãããšããµãŒããŒäžã§ã³ãŒãããªã¢ãŒãã§å®è¡ã§ãããããã¢ããªã±ãŒã·ã§ã³ããµãŒããŒã«äŸµå
¥ãããæ»æè
ã«ãšã£ãŠäºæããªãèŽãç©ã«ãªãå¯èœæ§ããããŸãã 远å ã®ã»ãã¥ãªãã£å¯ŸçãšããŠããã©ãŠã¶ãŒã§å®è¡äžã®ãããã¬ãŒãéããããæåã®äœ¿çšæã«ãPinkã³ãŒããèŠæ±ãããŸããããã¯ã flask run
ã³ãã³ãã®åºåã§ç¢ºèªã§ããŸãã
ãããã°ã¢ãŒãã«ã€ããŠèª¬æããŠããã®ã§ããããã°ã¢ãŒãã§æå¹ã«ãªã2çªç®ã®éèŠãªæ©èœã§ããåèµ·åã«ã€ããŠèšåããå¿
èŠããããŸãã ããã¯ããœãŒã¹ãã¡ã€ã«ã倿Žããããšãã«ã¢ããªã±ãŒã·ã§ã³ãèªåçã«åèµ·åããéåžžã«äŸ¿å©ãªéçºæ©èœã§ãã flask run
ããããã°ã¢ãŒãã§å®è¡ãããšãã¢ããªã±ãŒã·ã§ã³ã§äœæ¥ãç¶ããããšãã§ãããã¡ã€ã«ãä¿åãããã³ã«ã¢ããªã±ãŒã·ã§ã³ãåèµ·åããŠæ°ããã³ãŒããååŸããŸãã
ã«ã¹ã¿ã ãšã©ãŒããŒãž
Flaskã¯ãã«ã¹ã¿ã ãšã©ãŒããŒãžãäœæããããã®ã¢ããªã±ãŒã·ã§ã³ã¡ã«ããºã ãæäŸããããããŠãŒã¶ãŒã¯åçŽã§éå±ãªããã©ã«ããèŠãå¿
èŠããããŸããã äŸãšããŠãæãäžè¬çãª2ã€ã®HTTPãšã©ãŒ404ããã³500ã®ã«ã¹ã¿ã ãšã©ãŒããŒãžãå®çŸ©ããŸãããã ä»ã®ãšã©ãŒã®ããŒãžã®å®çŸ©ãåãããã«æ©èœããŸãã
ã«ã¹ã¿ã ãšã©ãŒãã³ãã©ã宣èšããã«ã¯ã @errorhandler
ãã³ã¬ãŒã¿ã@errorhandler
ãŸãã æ°ããapp / errors.pyã¢ãžã¥ãŒã«ã«ãšã©ãŒãã³ãã©ãé
眮ããŸã ã
from flask import render_template from app import app, db @app.errorhandler(404) def not_found_error(error): return render_template('404.html'), 404 @app.errorhandler(500) def internal_error(error): db.session.rollback() return render_template('500.html'), 500
ãšã©ãŒé¢æ°ã¯è¡šç€ºé¢æ°ãšåæ§ã«æ©èœããŸãã ãããã®2ã€ã®ãšã©ãŒã«ã€ããŠã¯ãããããã®ãã³ãã¬ãŒãã®å
容ãè¿ããŸãã äž¡æ¹ã®é¢æ°ãããã¿ãŒã³ã®åŸã®2çªç®ã®å€ãã€ãŸããšã©ãŒã³ãŒãçªå·ãè¿ãããšã«æ³šæããŠãã ããã ãããŸã§ã«äœæãããã¹ãŠã®ãã¬ãŒã³ããŒã·ã§ã³é¢æ°ã«ã€ããŠãããã©ã«ãã§200ïŒæ£åžžçµäºã®ã¹ããŒã¿ã¹ã³ãŒãïŒãå¿
èŠãªããã2çªç®ã®æ»ãå€ã远å ããå¿
èŠã¯ãããŸããã§ããã ãããã¯çŸåšãšã©ãŒããŒãžã§ãããããå¿çã¹ããŒã¿ã¹ã³ãŒãã«ãããåæ ãããå¿
èŠããããŸãã
500çªç®ã®ãšã©ãŒã®ãšã©ãŒãã³ãã©ã¯ãããŒã¿ããŒã¹é害ãçºçããåŸã«åŒã³åºãããšãã§ããŸããããã¯ãå®éã«ã¯éè€ãããŠãŒã¶ãŒåã®æå³çãªã±ãŒã¹ãåå ã§ãã 倱æããããŒã¿ããŒã¹ã»ãã·ã§ã³ããã³ãã¬ãŒãã«ããããŒã¿ããŒã¹ã¢ã¯ã»ã¹ã«å¹²æžããªãããã«ãã»ãã·ã§ã³ããŒã«ããã¯ãçºè¡ããŸãã ããã«ãããã»ãã·ã§ã³ãã¯ãªãŒã³ãªç¶æ
ã«ãªã»ãããããŸãã
ãšã©ãŒ404ã®ãã³ãã¬ãŒãã¯æ¬¡ã®ãšããã§ãã
{% extends "base.html" %} {% block content %} <h1>File Not Found</h1> <p><a href="{{ url_for('index') }}">Back</a></p> {% endblock %}
ãããŠãããã¯500ãšã©ãŒã®1ã€ã§ãã
{% extends "base.html" %} {% block content %} <h1>An unexpected error has occurred</h1> <p>The administrator has been notified. Sorry for the inconvenience!</p> <p><a href="{{ url_for('index') }}">Back</a></p> {% endblock %}
äž¡æ¹ã®ãã³ãã¬ãŒãã¯base.html
ãã³ãã¬ãŒããç¶æ¿ããããããšã©ãŒããŒãžã¯éåžžã®ã¢ããªã±ãŒã·ã§ã³ããŒãžãšåãå€èгã«ãªããŸãã
ãããã®ãšã©ãŒãã³ãã©ãŒãFlaskã«ç»é²ããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ã®äœæåŸã«æ°ããapp/errors.py
ãã€ã³ããŒãããå¿
èŠããããŸãã
# ... from app import routes, models, errors
ã¿ãŒããã«ã»ãã·ã§ã³ã§FLASK_DEBUG = 0
ãèšå®ããåŸãå床ãŠãŒã¶ãŒåã®éè€ãšã©ãŒãçºçããå Žåã¯ãããè¯ããšã©ãŒããŒãžã衚瀺ãããŸãã

ãŸãã¯ããïŒ æŒç¿ãšããŠèªåã§äœããèãåºãããšããå§ãããŸãã

ã¡ãŒã«ãšã©ãŒ
FlaskãæäŸããããã©ã«ãã®ãšã©ãŒåŠçã®ãã1ã€ã®åé¡ã¯ãéç¥ããªãããšã§ãã ãšã©ãŒã¹ã¿ãã¯ãã¬ãŒã¹ã¯ç«¯æ«ã«åºåãããŸããã€ãŸãããµãŒããŒããã»ã¹ã®åºåããšã©ãŒæ€åºã®ããã«ç£èŠããå¿
èŠããããŸãã éçºäžã«ã¢ããªã±ãŒã·ã§ã³ãèµ·åããå Žåãããã¯æ£åžžã§ãããã¢ããªã±ãŒã·ã§ã³ãéçšãµãŒããŒã«ãããã€ããããšããã«èª°ãçµæã確èªããªããããããä¿¡é Œæ§ã®é«ããœãªã¥ãŒã·ã§ã³ãäœæããå¿
èŠããããŸãã
ãšã©ãŒã«ç©æ¥µçã«å¯Ÿå¿ããããšã¯éåžžã«éèŠã ãšæããŸãã ã¢ããªã±ãŒã·ã§ã³ã®è£œåçã§ãšã©ãŒãçºçããå Žåãããã«ç¥ãããã§ãã ãããã£ãŠãæåã®æ±ºå®ã¯ãé»åã¡ãŒã«ã¡ãã»ãŒãžã®ãšã©ãŒã¹ã¿ãã¯ãã¬ãŒã¹ã§ãšã©ãŒãçºçããçŽåŸã«é»åã¡ãŒã«ãéä¿¡ããããã«Flaskãæ§æããããšã§ãã
æåã®ã¹ãããã¯ãæ§æãã¡ã€ã«ã«é»åã¡ãŒã«ãµãŒããŒããŒã¿ã远å ããããšã§ãã
class Config(object): # ... MAIL_SERVER = os.environ.get('MAIL_SERVER') MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25) MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') ADMINS = ['your-email@example.com']
é»åã¡ãŒã«æ§æå€æ°ã«ã¯ããµãŒããŒãšããŒããæå·åãããæ¥ç¶ãæå¹ã«ãããã©ã°ããªãã·ã§ã³ã®ãŠãŒã¶ãŒåãšãã¹ã¯ãŒããå«ãŸããŸãã ç°å¢å€æ°ãžã®ãããã³ã°ãã5ã€ã®æ§æå€æ°ã掟çããŸãã é»åã¡ãŒã«ãµãŒããŒãç°å¢ã«ã€ã³ã¹ããŒã«ãããŠããªãå Žåããããé»åã¡ãŒã«ãšã©ãŒãç¡å¹ã«ããå¿
èŠããããšãããµã€ã³ãšããŠäœ¿çšããŸãã ã¡ãŒã«ãµãŒããŒã®ããŒããç°å¢å€æ°ã§æå®ã§ããŸãããèšå®ãããŠããªãå Žåã¯ãæšæºããŒã25ã䜿çšãããŸããã¡ãŒã«ãµãŒããŒã®è³æ Œæ
å ±ã¯ããã©ã«ãã§ã¯äœ¿çšãããŸããããå¿
èŠã«å¿ããŠæäŸã§ããŸãã ADMINS
æ§æADMINS
ã¯ããšã©ãŒã¬ããŒããåä¿¡ããé»åã¡ãŒã«ã¢ãã¬ã¹ã®ãªã¹ãã§ãããããç¬èªã®é»åã¡ãŒã«ã¢ãã¬ã¹ããã®ãªã¹ãã«å«ãŸããŠããå¿
èŠããããŸãã
Flaskã¯Python logging
ããã±ãŒãžã䜿çšããŠãã°ãä¿æããŸããããã®ããã±ãŒãžã«ã¯ãã§ã«ãã°ãã¡ãŒã«ã§éä¿¡ããæ©èœããããŸãã ãšã©ãŒãå«ãé»åã¡ãŒã«ãéä¿¡ããããã«ç§ãããªããã°ãªããªãããšã¯ã app.loggerã§ããFlaskãã°ãªããžã§ã¯ãã«SMTPHandlerã€ã³ã¹ã¿ã³ã¹ã远å ããããšã§ãã
import logging from logging.handlers import SMTPHandler # ... if not app.debug: if app.config['MAIL_SERVER']: auth = None if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']: auth = (app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD']) secure = None if app.config['MAIL_USE_TLS']: secure = () mail_handler = SMTPHandler( mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']), fromaddr='no-reply@' + app.config['MAIL_SERVER'], toaddrs=app.config['ADMINS'], subject='Microblog Failure', credentials=auth, secure=secure) mail_handler.setLevel(logging.ERROR) app.logger.addHandler(mail_handler)
ã芧ã®ãšãããã¢ããªã±ãŒã·ã§ã³ãapp.debug
ã§True
ãšããŠå®çŸ©ãããŠãããããã°ã¢ãŒããªãã§ã¢ããªã±ãŒã·ã§ã³ãå®è¡ãããå Žåãããã³æ§æã«é»åã¡ãŒã«ãµãŒããŒãååšããå Žåã«ã®ã¿ãé»åã¡ãŒã«ãã¬ãŒããªã³ã«ããŸããã
ã¡ãŒã«ã¬ãžã¹ãã©ã®ã»ããã¢ããã¯ãå€ãã®é»åã¡ãŒã«ãµãŒããŒã«ååšãã远å ã®ã»ãã¥ãªãã£èšå®ãåŠçããå¿
èŠããããããå€å°é¢åã§ãã ãã ããæ¬è³ªçã«ãäžèšã®ã³ãŒãã¯SMTPHandler
ã€ã³ã¹ã¿ã³ã¹ãäœæããèŠåãæ
å ±ããããã°ã¡ãã»ãŒãžã§ã¯ãªããšã©ãŒã¡ãã»ãŒãžã®ã¿ãéä¿¡ããããã«ã¬ãã«ãèšå®ããFlaskããapp.logger
æçµçã«æ·»ä»ããŸãã
ãã®é¢æ°ã®æ©èœãæ€èšŒããã«ã¯ã2ã€ã®ã¢ãããŒãããããŸãã æãç°¡åãªæ¹æ³ã¯ãPythonã®SMTPãããã°ãµãŒããŒã䜿çšããããšã§ãã ããã¯é»åã¡ãŒã«ã¡ãã»ãŒãžãåãå
¥ããåœã®ã¡ãŒã«ãµãŒããŒã§ãããéä¿¡ãã代ããã«ã³ã³ãœãŒã«ã«è¡šç€ºããŸãã ãã®ãµãŒããŒãèµ·åããã«ã¯ã2çªç®ã®ã¿ãŒããã«ã»ãã·ã§ã³ãéããæ¬¡ã®ã³ãã³ããå®è¡ããŸãã
(venv) $ python -m smtpd -n -c DebuggingServer localhost:8025
ãããã°SMTPãµãŒããŒãå®è¡ãããŸãŸã«ããŠãæåã®ã¿ãŒããã«ã«æ»ãã export
MAIL_SERVER = localhost
ããã³MAIL_PORT = 8025
ãset
ããŸãïŒMicrosoft Windowsã䜿çšããŠããå Žåã¯ã export
代ããã«set
ã䜿çšããŸãïŒã ã¢ããªã±ãŒã·ã§ã³ã¯ãããã°ã¢ãŒãã§é»åã¡ãŒã«ãéä¿¡ããªãããã FLASK_DEBUG
倿°FLASK_DEBUG
0
èšå®ãããŠãããããŸã£ããèšå®ãããŠããªãããšã確èªããŠãã ããã
ã¢ããªã±ãŒã·ã§ã³ãèµ·åããSQLAlchemyãšã©ãŒãå床çºçãããŠãåœã¡ãŒã«ãµãŒããŒãå®è¡ããŠããã¿ãŒããã«ã»ãã·ã§ã³ããšã©ãŒã¹ã¿ãã¯ã®å
šå
容ãå«ãé»åã¡ãŒã«ãã©ã®ããã«è¡šç€ºãããã確èªããŸãã
ãã®æ©èœã®2çªç®ã®ãã¹ãæ¹æ³ã¯ãå®éã®ã¡ãŒã«ãµãŒããŒãæ§æããããšã§ãã 以äžã¯ã Gmailã¢ã«ãŠã³ãã«ã¡ãŒã«ãµãŒããŒã䜿çšããããã®æ§æã§ãã
export MAIL_SERVER=smtp.googlemail.com export MAIL_PORT=587 export MAIL_USE_TLS=1 export MAIL_USERNAME=<your-gmail-username> export MAIL_PASSWORD=<your-gmail-password>
Microsoft Windowsã䜿çšããŠããå Žåã¯ãäžèšã®åæé ã§export
代ããã«set
ã䜿çšããŠãã ããã
Gmailã¢ã«ãŠã³ããžã®ã¢ã¯ã»ã¹ããå®å
šæ§ã®äœãã¢ããªãã«æç€ºçã«èš±å¯ããªãéããGmailã¢ã«ãŠã³ãã®ã»ãã¥ãªãã£æ©èœã«ãããã¢ããªã±ãŒã·ã§ã³ããã®ã¡ãŒã«éä¿¡ã劚ããããå ŽåããããŸãã ããã«ã€ããŠã¯ããã§èªãããšãã§ããŸããã¢ã«ãŠã³ãã®ã»ãã¥ãªãã£ãå¿é
ãªå Žåã¯ãé»åã¡ãŒã«ããã§ãã¯ããããã ãã«æ§æããã»ã«ã³ããªã¢ã«ãŠã³ããäœæãããããã®ãã¹ãã®éãå®å
šæ§ã®äœãã¢ããªã±ãŒã·ã§ã³ã®ã¢ã¯ã»ã¹èš±å¯ãäžæçã«æå¹ã«ããŠããããã©ã«ãã«æ»ãããšãã§ããŸãã
ãã¡ã€ã«ãžã®ãã®ã³ã°
é»åã¡ãŒã«ã®ãšã©ãŒãååŸããããšã¯äŸ¿å©ã§ãããæã«ã¯ååã§ã¯ãããŸããã Pythonã®äŸå€ã§ã¯èª¬æãããŠããããé倧ãªåé¡ã§ã¯ãªãé害ã®å ŽåããããŸããããããã°ã®ç®çã§ä¿åã§ããã»ã©è峿·±ãå ŽåããããŸãã ãã®ãããã¢ããªã±ãŒã·ã§ã³ã®ãã°ãã¡ã€ã«ããµããŒãããŸãã
ä»åã¯RotatingFileHandler
ã¿ã€ãã®å¥ã®ãã³ãã©ãŒã®ãã®ã³ã°ãæå¹ã«ããã«ã¯ãé»åã¡ãŒã«ãã³ãã©ãŒãšåæ§ã«ã¢ããªã±ãŒã·ã§ã³ã®ãã¬ãŒãæå¹RotatingFileHandler
ããå¿
èŠããããŸãã
# ... from logging.handlers import RotatingFileHandler import os # ... if not app.debug: # ... if not os.path.exists('logs'): os.mkdir('logs') file_handler = RotatingFileHandler('logs/microblog.log', maxBytes=10240, backupCount=10) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) app.logger.info('Microblog startup')
microblog.logãšãããã°ãã¡ã€ã«ããäœæããŠããªããã°ãã£ã¬ã¯ããªã«äœæããŠããŸãã
RotatingFileHandler
ã¯ã©ã¹ã¯ããã°ãäžæžãããã¢ããªã±ãŒã·ã§ã³ãé·æéå®è¡ãããŠããå Žåã«ãã°ãã¡ã€ã«ã倧ãããªããããªãããã«ããã®ã§äŸ¿å©ã§ãã ãã®å Žåããã°ãã¡ã€ã«ã®ãµã€ãºã10 KBã«å¶éããæåŸã®10åã®ãã°ãã¡ã€ã«ãããã¯ã¢ãããšããŠä¿åããŸãã
logging.Formatter
ã¯ã©ã¹ã¯ããã°ã¡ãã»ãŒãžåœ¢åŒã®ã«ã¹ã¿ãã€ãºãæäŸããŸãã ãããã®ã¡ãã»ãŒãžã¯ãã¡ã€ã«ã«éä¿¡ããããããã§ããã ãå€ãã®æ
å ±ãå«ããããã«ããŸãã ãã®ãããã¿ã€ã ã¹ã¿ã³ãããã°ã¬ãã«ã
ã¡ãã»ãŒãžããœãŒã¹ãã¡ã€ã«ãããã³ãã°ãšã³ããªã®çºä¿¡å
ã®è¡çªå·ã
ãã®ã³ã°ãããã«äŸ¿å©ã«ããããã«ãã¢ããªã±ãŒã·ã§ã³ãã¬ãŒãšãã¡ã€ã«ãã³ãã©ãŒã®äž¡æ¹ã§ããã®ã³ã°ã¬ãã«ãINFO
ã«ããŽãªã«äžããŸãã ä»èš³ã«ããŽãªã«ç²ŸéããŠããªãå Žåããããã¯éå€§åºŠã®æé ã§DEBUG
ã INFO
ã WARNING
ã ERROR
ããã³CRITICAL
ã§ãã
ãã°ãã¡ã€ã«ã®æåã®äŸ¿å©ãªäœ¿çšæ³ãšããŠããµãŒããŒã¯èµ·åãããã³ã«ãã°ã«è¡ãæžã蟌ã¿ãŸãã å®çšŒåãµãŒããŒã§ã¢ããªã±ãŒã·ã§ã³ãå®è¡ãããšããããã®ãã°ãšã³ããªã¯ãµãŒããŒãåèµ·åãããææã瀺ããŸãã
ãŠãŒã¶ãŒåã®ä¿®æ£
ãŠãŒã¶ãŒåã®éè€ãšã©ãŒãé·ãããŸã ãã®ãããªãšã©ãŒãåŠçããã¢ããªã±ãŒã·ã§ã³ãæºåããæ¹æ³ã瀺ããã®ã§ãããããä¿®æ£ããããšãã§ããŸãã
èŠããŠãããªãã RegistrationForm
ãã§ã«ãŠãŒã¶ãŒåããã§ãã¯ããŠããŸãããç·šéãã©ãŒã ã®èŠä»¶ã¯å°ãç°ãªããŸãã ç»é²æã«ããã©ãŒã ã«å
¥åãããŠãŒã¶ãŒåãããŒã¿ããŒã¹ã«ååšããªãããšã確èªããå¿
èŠããããŸãã ãããã¡ã€ã«ã®ç·šéãã©ãŒã ã§ã¯ãåããã§ãã¯ãå®è¡ããå¿
èŠããããŸãããäŸå€ã1ã€ãããŸãã ãŠãŒã¶ãŒãå
ã®ãŠãŒã¶ãŒåããã®ãŸãŸæ®ããå Žåããã®ãŠãŒã¶ãŒåã¯æ¢ã«ãã®ãŠãŒã¶ãŒã«å²ãåœãŠãããŠããããããã§ãã¯ã§è§£æ±ºããå¿
èŠããããŸãã 以äžã«ããã®ãã©ãŒã ã®ãŠãŒã¶ãŒåãã§ãã¯ã®å®è¡æ¹æ³ã瀺ããŸãã
class EditProfileForm(FlaskForm): username = StringField('Username', validators=[DataRequired()]) about_me = TextAreaField('About me', validators=[Length(min=0, max=140)]) submit = SubmitField('Submit') def __init__(self, original_username, *args, **kwargs): super(EditProfileForm, self).__init__(*args, **kwargs) self.original_username = original_username def validate_username(self, username): if username.data != self.original_username: user = User.query.filter_by(username=self.username.data).first() if user is not None: raise ValidationError('Please use a different username.')
å®è£
ã¯ãå
ã®ãŠãŒã¶ãŒåãåŒæ°ãšããŠåããã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ãŒã®ã¹ãŒããŒé¢æ°ã§ããç¹å¥ãªæ€èšŒã¡ãœããã§å®è¡ãããŸãã ãã®ãŠãŒã¶ãŒåã¯ã€ã³ã¹ã¿ã³ã¹å€æ°ãšããŠä¿åããã validate_username()
ã¡ãœããã§validate_username()
ãããŸãã ãã©ãŒã ã«å
¥åããããŠãŒã¶ãŒåãå
ã®ãŠãŒã¶ãŒåãšäžèŽããå ŽåãããŒã¿ããŒã¹ã®éè€ããã§ãã¯ããçç±ã¯ãããŸããã
ãã®æ°ããæ€èšŒã¡ãœããã䜿çšããã«ã¯ããã©ãŒã ãªããžã§ã¯ããäœæããããã¥ãŒé¢æ°ã«å
ã®ãŠãŒã¶ãŒååŒæ°ã远å ããå¿
èŠããããŸãã
@app.route('/edit_profile', methods=['GET', 'POST']) @login_required def edit_profile(): form = EditProfileForm(current_user.username) # ...
ããã§ãšã©ãŒãä¿®æ£ãããã»ãšãã©ã®å Žåãç·šéãããã¡ã€ã«ã®åœ¢ã§ã®éè€ã鲿¢ãããŸãã ããã¯ã2ã€ä»¥äžã®ããã»ã¹ãããŒã¿ããŒã¹ã«åæã«ã¢ã¯ã»ã¹ãããšåäœããªãå Žåããããããçæ³çãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãããŸããã ãã®ç¶æ³ã§ã¯ãç«¶åç¶æ
ãæ€èšŒã«ã€ãªããå¯èœæ§ããããŸããããã°ãããããšãããŒã¿ããŒã¹ã®ååã倿Žããããšãããšå¥ã®ããã»ã¹ã«ãã£ãŠæ¢ã«å€æŽãããŠããããŠãŒã¶ãŒã®ååã倿Žã§ããŸããã å€ãã®ãµãŒããŒããã»ã¹ãæã€éåžžã«ããžãŒãªã¢ããªã±ãŒã·ã§ã³ãé€ããŠãããã¯ããããããã«ãªãã®ã§ãä»ã®ãšããããã«ã€ããŠã¯å¿é
ããŸããã
ãã®æç¹ã§ããšã©ãŒãå床åçŸããŠããã©ãŒã æ€èšŒã¡ãœãããã©ã®ããã«ãšã©ãŒãé²ããã確èªã§ããŸãã
<<<å æ¬¡>>>
PS
ãšã©ãŒåŠç
翻蚳è
ãã
管çè
ãžã®ãšã©ãŒã¡ãã»ãŒãžã®åä¿¡ãã¡ãŒã«ã§ç¢ºèªããããšã«ããŸããã ãã®ããã routes.py
ã¢ãžã¥ãŒã«ãå°ç¡ãã«ããŸããã ãã®éåžžã«ãç Žæãã®ããã def edit_profile()
åã«@app.route('/edit_profile', methods=['GET', 'POST'])
ãã³ã¬ãŒã¿ãŒ@app.route('/edit_profile', methods=['GET', 'POST'])
ãã³ã¡ã³ãã¢ãŠãããŸããã ãã®çµæããšã©ãŒãçºçãããã¹ãŠãã°ãã¡ã€ã«ã«èšé²ãããŸããããæçŽã¯å±ããŸããã§ããã Python 3.3ã䜿çšããŠããŸãã ãããããããã¯æ°ããããŒãžã§ã³ã§ã¯çºçããŸããã ãããããã·ã¢èªã¬ã€ã¢ãŠãã®Windows 7ã§ã¯ããããèµ·ãããŸããã
管çè
ã«ã¡ãã»ãŒãžãéä¿¡ããããšãããšãã«ãã¢ããªã±ãŒã·ã§ã³ãã¡ãã»ãŒãžã®äœæäžã«ãšã³ã³ãŒããšã©ãŒãåãåããŸããã ã³ã³ãœãŒã«ãŠã£ã³ããŠã«ã¯æ¬¡ã®è¡ãå«ãŸããŠããŸããã

ã芧ã®ãšããããªã³ã¯ã¯ä»®æ³ç°å¢ã§ã¯ãªããæšæºã®Pythonã®ãã£ã¬ã¯ããªãæããŸãã
ããŒãžã§ã³3ã§ã®logging
ã¯æšæºã®Pythonã©ã€ãã©ãªã§ããããã pip
ã䜿çšããŠã€ã³ã¹ããŒã«ããå¿
èŠã¯ãããŸããã
æšæºã¢ãžã¥ãŒã«ã«ã€ããŠãŸããPyPIã«ãããã®ã³ã°ã¢ãžã¥ãŒã«ã¯å»æ¢ãããŠãããPython3äºæã§ã¯ãããŸããã
ïŒREADMEãã¡ã€ã«ã«ãããšããã®ææ°ããŒãžã§ã³ã¯2005幎3æ2æ¥ã«ãªãªãŒã¹ãããŸãããïŒ
ãããã£ãŠããã®ã³ã°ãã€ã³ã¹ããŒã«ããããšããªãã§ãã ããã
æšæºã©ã€ãã©ãªã®æ°ããã¢ãžã¥ãŒã«ãåœç¶ã®ããšãšèããŠãã ããã ä»®æ³ã©ã€ãã©ãªã§äœ¿çšããããšãéèŠãªå Žåã
venvã«ã³ããŒããåŸã lib logging
ä»®æ³ç°å¢ããã€ã³ããŒããããŸã

åã³ãšã©ãŒãçºçããŸã

logging
ä»®æ³ã«ãªããŸããã ãã ãã smtplib
æšæºã§ãã
ãã¹ãŠã®ã©ã€ãã©ãªãæšæºç°å¢ããä»®æ³ç°å¢ã«ãã©ãã°ããå¿
èŠã¯ãªããšæããŸãã
ããã«ãããšã©ãŒã¯æ¶ããŸããã
æšæºã®ã¡ãŒã«ã¢ãžã¥ãŒã«ã«ã€ããŠã¡ãã»ãŒãžã®ãšã³ã³ãŒãã®åé¡ã¯ãæšæºã®email
ããã±ãŒãžã䜿çšããŠãåªå
ãšã³ã³ãŒãã瀺ãã¡ãã»ãŒãžãäœæããããšã§è§£æ±ºãããŸãã
ãã®ããã±ãŒãžã®ã€ã³ã¿ãŒãããããã®äŸã次ã«ç€ºããŸãã
# -*- coding: utf-8 -*- from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText import quopri def QuoHead(String): s = quopri.encodestring(String.encode('UTF-8'), 1, 0) return "=?utf-8?Q?" + s.decode('UTF-8') + "?=" FIOin = " " emailout = "some@test.ru" emailin = "some2@test.ru" msg = MIMEMultipart() msg["Subject"] = QuoHead(" " + FIOin).replace('=\n', '') msg["From"] = (QuoHead(" ") + " <" + emailout + ">").replace('=\n', '') msg["To"] = (QuoHead(FIOin) + " <" + emailin + ">").replace('=\n', '') m = """ . . , .""" text = MIMEText(m.encode('utf-8'), 'plain', 'UTF-8') msg.attach(text) print(msg.as_string())
ãããããšã©ãŒã¡ãã»ãŒãžãéä¿¡ããããã«ãããã©ã®ããã«é©çšããã®ã§ããïŒïŒ
誰ããèšäºã®ã³ã¡ã³ãã§ææ¡ãããããããŸããã
flask-mail
. logging
smtplib
. smtplib.py
.
encode('utf-8')

, -, .
