æè»æ§ãšæ¡åŒµæ§ãå Œãåãã Web ã¢ããªã±ãŒã·ã§ã³éçºã®éžæè¢ãæ¢ã
ã¯ããã«ïŒTurboGears ãšã¯ïŒ ð€
TurboGears ã¯ãPython ã§æžããããªãŒãã³ãœãŒã¹ã® Web ã¢ããªã±ãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ã§ããMVC (Model-View-Controller) ã¢ãŒããã¯ãã£ãã¿ãŒã³ã«åºã¥ããŠãããWeb ã¢ããªã±ãŒã·ã§ã³éçºã«å¿ èŠãªã³ã³ããŒãã³ããçµ±åçã«æäŸããããšãç®æããŠããŸãããã°ãã°ããã«ã¹ã¿ãã¯ããã¬ãŒã ã¯ãŒã¯ãšããŠåé¡ãããŸããããã®ã³ã³ããŒãã³ãã¯æè»ã«éžæã»çœ®æå¯èœã§ããããã¡ã¬ãã¬ãŒã ã¯ãŒã¯ããšãåŒã°ããŸãã
TurboGears ã®å²åŠã¯ãæ¢åã®åªããã³ã³ããŒãã³ãïŒã©ã€ãã©ãªïŒãçµã¿åãããããšã§ãè¿ éãªéçºãšé«ãã¡ã³ããã³ã¹æ§ãäž¡ç«ãããããšã«ãããŸããéçºè ã¯ãå®è©ã®ããã©ã€ãã©ãªçŸ€ã®æ©æµãåãã€ã€ããã¬ãŒã ã¯ãŒã¯ãæäŸããçµ±åãããç°å¢ã®äžã§å¹ççã«éçºãé²ããããšãã§ããŸãã
ãã®ããã°èšäºã§ã¯ãTurboGears ã®æŽå²ãç¹åŸŽãäž»èŠã³ã³ããŒãã³ããåºæ¬çãªäœ¿ãæ¹ããããŠä»ã®ãã¬ãŒã ã¯ãŒã¯ãšã®æ¯èŒãªã©ãéããŠããã®é åãšå¯èœæ§ãæ·±ãæãäžããŠãããŸããð
TurboGears ã®æŽå²ãšé²å ð°ïž
TurboGears ã¯ãKevin Dangoor ã«ãã£ãŠ 2005 幎ã«æåã®ããŒãžã§ã³ããªãªãŒã¹ãããŸãããåœåã¯ãåœæ人æ°ã ã£ã Ruby on Rails ã«åœ±é¿ãåããPython ã«ãããåæ§ã®è¿ éãªéçºäœéšãæäŸããããšãç®æããŠããŸããã
TurboGears 1.x ç³»
åæã® TurboGears (1.0, 1.1, 1.5 ãªã©) ã¯ã以äžã®äž»èŠã³ã³ããŒãã³ãã§æ§æãããŠããŸããã
- Object Relational Mapper (ORM): SQLObject (ããã©ã«ã) ãŸã㯠SQLAlchemy
- Templating Engine: Kid (ããã©ã«ã) ãŸã㯠Genshi
- Routing/Controller: CherryPy
- JavaScript Library Integration: MochiKit
ãããã®ã³ã³ããŒãã³ããçµã¿åãããèšå®ãããèŠçŽ (Convention over Configuration) ã®ååãåãå ¥ããããšã§ãéçºã®çç£æ§ãé«ããŸãããç¹ã«ããŠã£ãžã§ããã·ã¹ãã (ToscaWidgets ã®å身) ã¯ããã©ãŒã çæãªã©ã容æã«ããç¹åŸŽçãªæ©èœã®äžã€ã§ããã
ããããæ代ã®å€åãšãšãã«ãWeb æšæºã®é²åãWSGI ã®æ®åããããŠäŸåã³ã³ããŒãã³ãèªèº«ã®é²åãªã©ãæ§ã ãªèª²é¡ãé¡åšåããŠããŸããã
TurboGears 2.x ç³»ïŒåèšèšãšã¢ããã€ãŒãŒã·ã§ã³ âš
ãããã®èª²é¡ã«å¯Ÿå¿ãããããTurboGears ããŒã ã¯å€§å¹ ãªåèšèšãè¡ãã2008 幎é ãã TurboGears 2 ã®éçºãéå§ããŸãããTurboGears 2 ã¯ãTurboGears 1 ã®æèšã掻ããã€ã€ãããæšæºçã§æè»ããã€åŒ·åãªãã¬ãŒã ã¯ãŒã¯ãç®æããŸããã
TurboGears 2.0 㯠2009 幎ã«æ£åŒãªãªãŒã¹ããã以äžã®ç¹ãäž»ãªå€æŽç¹ãšãªããŸããã
- WSGI ãã€ãã£ã察å¿: Pylons (åŸã® Pyramid ã®å身ã®äžã€) ãããŒã¹ãšããWSGI ã«å®å šæºæ ããŸãããããã«ãããããã«ãŠã§ã¢ã®å©çšãªã©ã容æã«ãªããŸããã
- ORM: SQLAlchemy ãæšæºãã€æšå¥šãšãªããŸããã
- Templating Engine: Genshi ãæšæºãšãªããŸããããMako ã Jinja2 ãªã©ãä»ã®ãã³ãã¬ãŒããšã³ãžã³ã容æã«å©çšå¯èœã«ãªããŸããã
- Controller/Routing: Repoze.what / Repoze.who (èªèšŒã»èªå¯)ãWebOb (ãªã¯ãšã¹ã/ã¬ã¹ãã³ã¹ãªããžã§ã¯ã) ãªã©ãããæšæºç㪠WSGI ã³ã³ããŒãã³ããæ¡çšããŸãããã«ãŒãã£ã³ã°ã«ã¯ Routes ã䜿ãããŠããŸãã
- ãŠã£ãžã§ããã·ã¹ãã : ToscaWidgets (åŸã« ToscaWidgets2 ãžé²å) ãå°å ¥ããããã匷åã§æè»ãªãŠã£ãžã§ããæ©èœãæäŸããŸããã
- ã³ãã³ãã©ã€ã³ããŒã«: Paster (åŸã« Gearbox ãžç§»è¡) ã«ãããããžã§ã¯ã管çã
TurboGears 2 ã¯ãTurboGears 1 ã®ãããã«äœ¿ãããå©äŸ¿æ§ãç¶æãã€ã€ãã³ã³ããŒãã³ãã®ç¬ç«æ§ãé«ããéçºè ãããèªç±ã«æè¡éžæãè¡ããæè»æ§ãæäŸããŸããããã®ã¢ãŒããã¯ãã£ã¯ãçŸåšã® TurboGears (2.4.x ç³»ãªã©) ã«ãåŒãç¶ãããŠããŸãã
ææ°ã®å®å®çãªãªãŒã¹ã«é¢ããæ å ±ã¯ãå ¬åŒãŠã§ããµã€ãã PyPI ã§ç¢ºèªããã®ãæã確å®ã§ããïŒçŸæç¹ã§ã®ææ°æ å ±ã¯å¥é確èªãå¿ èŠã§ãïŒ
TurboGears ã®äž»ãªç¹åŸŽ ð¡
TurboGears ã¯å€ãã®ç¹åŸŽãæã£ãŠããŸãããããã§ã¯ç¹ã«éèŠãªç¹ãããã€ã玹ä»ããŸãã
ãã«ã¹ã¿ãã¯ã§ãããªããæè»
Web ã¢ããªã±ãŒã·ã§ã³éçºã«å¿ èŠãªããŒã«ïŒORMããã³ãã¬ãŒããšã³ãžã³ãã«ãŒãã£ã³ã°ãèªèšŒã»èªå¯ããã©ãŒã åŠçãªã©ïŒãäžéãæã£ãŠããŸããããããåã³ã³ããŒãã³ãã¯ç¬ç«æ§ãé«ããå¿ èŠã«å¿ããŠä»ã®ã©ã€ãã©ãªã«çœ®ãæããããç¡å¹åãããããããšãå¯èœã§ããããã«ããããããã«å§ãããããå©äŸ¿æ§ãšããåŸããã«ã¹ã¿ãã€ãºã§ãããæè»æ§ãäž¡ç«ããŠããŸãã
ã³ã³ããŒãã³ãããŒã¹
SQLAlchemy, Genshi/Kajiki, ToscaWidgets2 ãªã©ãå®çžŸã®ããç¬ç«ããã©ã€ãã©ãªãçµã¿åãããŠæ§æãããŠããŸããããã«ãããååéã§æé«ã®ããŒã«ãå©çšã§ããã¡ãªããããããŸãããŸãããããã®ã©ã€ãã©ãªã«é¢ããç¥èã¯ãTurboGears 以å€ã®ãããžã§ã¯ãã§ã圹ç«ã¡ãŸãã
匷åãªãŠã£ãžã§ããã·ã¹ãã (ToscaWidgets2)
ãã©ãŒã ã®çæãããªããŒã·ã§ã³ãã¬ã³ããªã³ã°ãå¹çåãã ToscaWidgets2 ãçµ±åãããŠããŸããHTMLãCSSãJavaScript ãã«ãã»ã«åããåå©çšå¯èœãªã³ã³ããŒãã³ããäœæã§ããè€é㪠UI ã®æ§ç¯ãæ¯æŽããŸãã
ãã©ã°ã€ã³ã¢ãŒããã¯ãã£
TurboGears ã¯æ¡åŒµæ§ãé«ãããã©ã°ã€ã³ã«ãã£ãŠæ©èœãè¿œå ã§ããŸããèªèšŒæ¹æ³ã®è¿œå ã管çç»é¢ã®å°å ¥ãAPI æ©èœã®åŒ·åãªã©ãæ§ã ãªãã©ã°ã€ã³ãã³ãã¥ããã£ã«ãã£ãŠéçºãããŠããŸãã
ãã«ãããŒã¿ããŒã¹å¯Ÿå¿
ORM ãšã㊠SQLAlchemy ãæšæºæ¡çšããŠãããããPostgreSQL, MySQL, SQLite, Oracle ãªã©ãSQLAlchemy ããµããŒãããå€ãã®ããŒã¿ããŒã¹ãå©çšã§ããŸãã
ã³ãã³ãã©ã€ã³ããŒã« (Gearbox)
ãããžã§ã¯ãã®äœæããµãŒããŒã®èµ·åãããŒã¿ããŒã¹ãã€ã°ã¬ãŒã·ã§ã³ãã³ãŒãçæãªã©ã®ã¿ã¹ã¯ãå®è¡ããããã®åŒ·åãªã³ãã³ãã©ã€ã³ã€ã³ã¿ãŒãã§ãŒã¹ `gearbox` ãæäŸãããŠããŸãã
äž»èŠã³ã³ããŒãã³ã解説 ð§
TurboGears 2.x ç³»ã®äž»èŠãªã³ã³ããŒãã³ããèŠãŠãããŸãããã
Web Server Gateway Interface (WSGI)
TurboGears 2 㯠WSGI ãã€ãã£ããªãã¬ãŒã ã¯ãŒã¯ã§ããããã«ãããæ§ã 㪠WSGI ãµãŒã㌠(Waitress, Gunicorn, uWSGI ãªã©) äžã§åäœããWSGI ããã«ãŠã§ã¢ã容æã«çµã¿èŸŒãããšãã§ããŸãããªã¯ãšã¹ããšã¬ã¹ãã³ã¹ã®åŠçã«ã¯ WebOb ã©ã€ãã©ãªãå éšã§äœ¿çšãããŠããŸãã
ã«ãŒãã£ã³ã° (Routes)
URL ãã£ã¹ãããïŒç¹å®ã® URL ãã©ã®ã³ã³ãããŒã©ãŒã®ã¢ã¯ã·ã§ã³ã«çµã³ã€ãããïŒã«ã¯ Routes ã©ã€ãã©ãªã䜿ãããŠããŸããæè»ãª URL ãã¿ãŒã³ã®å®çŸ©ããURL çææ©èœãæäŸããŸãã
# config/routing.py ã®äŸ (äžéš)
from tg import routes
def add_routes(app_config, setup_method):
# ããã©ã«ãã®ã«ãŒããæ¥ç¶
routes.connect_default(app_config['package'].RootController,
controllers=app_config['package'])
# ã«ã¹ã¿ã ã«ãŒãã®è¿œå äŸ
routes.connect('/about', controller='root', action='about')
routes.connect('/users/{user_id}', controller='user', action='show')
ã³ã³ãããŒã©ãŒ (Controller)
ãŠãŒã¶ãŒããã®ãªã¯ãšã¹ããåãåããããžãã¹ããžãã¯ãå®è¡ããé©åãªã¬ã¹ãã³ã¹ïŒéåžžã¯ãã³ãã¬ãŒãã®ã¬ã³ããªã³ã°çµæïŒãè¿ã圹å²ãæ ããŸããTurboGears ã®ã³ã³ãããŒã©ãŒã¯ãPython ã®ã¯ã©ã¹ãšã¡ãœãããšããŠå®è£ ãããŸãã
# myapp/controllers/root.py ã®äŸ
from tg import expose, flash, require, url, lurl
from tg import request, redirect, tmpl_context
from tg.i18n import ugettext as _, lazy_ugettext as l_
from tg.exceptions import HTTPFound
from tg import predicates
# ãããžã§ã¯ãã®ã¢ãã«ããŠã£ãžã§ãããªã©ãã€ã³ããŒã
# from myapp import model
# from myapp.controllers.error import ErrorController
# from myapp.widgets.movie_form import MovieForm # äŸ
class RootController:
# error = ErrorController() # ãšã©ãŒã³ã³ãããŒã©ãŒã®äŸ
@expose('myapp.templates.index') # 䜿çšãããã³ãã¬ãŒããæå®
def index(self):
"""Handle the front-page."""
return dict(page='index') # ãã³ãã¬ãŒãã«æž¡ãèŸæž
@expose('myapp.templates.about')
def about(self):
"""Handle the 'about' page."""
return dict(page='about')
# ... ä»ã®ã¢ã¯ã·ã§ã³ã¡ãœãã ...
@expose()
ãã³ã¬ãŒã¿ã¯ãã¡ãœããã Web çµç±ã§ã¢ã¯ã»ã¹å¯èœã«ãã䜿çšãããã³ãã¬ãŒããæå®ããŸããä»ã«ãèªèšŒã»èªå¯ã®ããã® @require()
ããJSON ãè¿ãããã® @expose('json')
ãªã©ãæ§ã
ãªãã³ã¬ãŒã¿ãçšæãããŠããŸãã
ãã³ãã¬ãŒããšã³ãžã³ (Kajiki / Genshi ãªã©)
ã³ã³ãããŒã©ãŒããæž¡ãããããŒã¿ã䜿ã£ãŠãæçµç㪠HTML ã¬ã¹ãã³ã¹ãçæããŸããTurboGears 2.4 以éã§ã¯ Kajiki ãããã©ã«ãã®ãã³ãã¬ãŒããšã³ãžã³ãšãªã£ãŠããŸããKajiki 㯠Genshi ã®åŸç¶ã§ãããXML/HTML ããŒã¹ã®æ§æãæã¡ãPython ã³ãŒããåã蟌ãããšãã§ããŸããGenshi ãåŒãç¶ãå©çšå¯èœã§ãèšå®ãå€æŽããã° Mako ã Jinja2 ãªã©ã䜿çšã§ããŸãã
<!-- myapp/templates/index.xhtml (Kajikiã®äŸ) -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<!-- head éšåãªã©ã¯ layout.xhtml ããç¶æ¿ãããæ³å® -->
<body>
<div class="container">
<h1 class="title">ãããã TurboGears ãžïŒ</h1>
<p>çŸåšã®ããŒãž: ${page}</p>
<!-- æ¡ä»¶åå²ã®äŸ -->
<p py:if="user">ããã«ã¡ã¯ã${user.name} ããïŒ</p>
<p py:else="">ãã°ã€ã³ããŠããŸããã</p>
<!-- ã«ãŒãã®äŸ -->
<ul py:if="items">
<li py:for="item in items">${item}</li>
</ul>
</div>
</body>
</html>
Object Relational Mapper (SQLAlchemy)
ããŒã¿ããŒã¹ãšã®å¯Ÿè©±ãæœè±¡åããPython ãªããžã§ã¯ããéããŠããŒã¿ããŒã¹æäœãè¡ããããã«ããŸããSQLAlchemy ã¯éåžžã«åŒ·åã§æè»ãª ORM ã§ãããè€éãªã¯ãšãªãããŒã¿ããŒã¹ã¹ããŒãã®ç®¡ç (Alembic ãšã®é£æº) ããµããŒãããŸãã
# myapp/model/models.py ã®äŸ
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Unicode, Integer, DateTime
from sqlalchemy.orm import relationship, backref
from myapp.model import DeclarativeBase, metadata
class User(DeclarativeBase):
__tablename__ = 'users'
uid = Column(Integer, primary_key=True)
user_name = Column(Unicode(16), unique=True, nullable=False)
email_address = Column(Unicode(255), unique=True, nullable=False)
display_name = Column(Unicode(255))
password = Column(Unicode(80))
created = Column(DateTime)
# ä»ã®ã¢ãã«ãšã®ãªã¬ãŒã·ã§ã³ã·ããäŸ
# groups = relationship('Group', secondary=user_group_table, backref='users')
def __repr__(self):
return f'<User: name={self.user_name}, email={self.email_address}>'
# ... ä»ã®ã¢ãã«å®çŸ© ...
def init_model(engine):
"""ããŒã¿ããŒã¹ã»ãã·ã§ã³ãåæå"""
DBSession.configure(bind=engine)
# DBSession ã¯éåžžãmyapp/model/__init__.py ã§å®çŸ©ãããã»ãã·ã§ã³ãªããžã§ã¯ã
# from sqlalchemy.orm import scoped_session, sessionmaker
# DBSession = scoped_session(sessionmaker())
ã¢ãã«ã¯ã©ã¹ãå®çŸ©ããinit_model
é¢æ°ã§ããŒã¿ããŒã¹ãšã³ãžã³ãšã®æ¥ç¶ãèšå®ããŸããã³ã³ãããŒã©ãŒå
ã§ã¯ããã® DBSession
ãéããŠããŒã¿ããŒã¹æäœãè¡ããŸãã
ãŠã£ãžã§ãã (ToscaWidgets2)
HTML ãã©ãŒã ããã®ä»ã® UI ã³ã³ããŒãã³ãã Python ã³ãŒãã§å®çŸ©ã»ç®¡çããããã®ã©ã€ãã©ãªã§ãããã©ãŒã ãã£ãŒã«ãã®å®çŸ©ãããªããŒã·ã§ã³ã«ãŒã«ã®èšå®ãã¬ã³ããªã³ã°ããžãã¯ãªã©ãã«ãã»ã«åã§ããŸãã
# myapp/widgets/movie_form.py ã®äŸ
import tw2.forms as twf
import tw2.core as twc
# ããªããŒã¿ãŒã®ã€ã³ããŒãäŸ
# from formencode import validators
class MovieForm(twf.Form):
# CSRF察çãã£ãŒã«ã (èªåã§è¿œå ãããããšãå€ã)
# class HiddenFields(twf.WidgetsList):
# _csrf_token = twf.HiddenField()
class Fields(twf.WidgetsList):
title = twf.TextField(label='ã¿ã€ãã«', validator=twc.Required)
year = twf.TextField(label='å
¬é幎', validator=validators.IntValidator(min=1900)) # formencodeã䜿ãå Žå
director = twf.TextField(label='ç£ç£')
# ã¢ã¯ã·ã§ã³ãã¿ã³
action = '/movies/save' # ãã©ãŒã ã®éä¿¡å
URL
submit = twf.SubmitButton(value='ä¿å')
ã³ã³ãããŒã©ãŒã§ãã®ãã©ãŒã ãã€ã³ã¹ã¿ã³ã¹åãããã³ãã¬ãŒãã«æž¡ããŠã¬ã³ããªã³ã°ããŸããããªããŒã·ã§ã³ããã¬ãŒã ã¯ãŒã¯ãçµ±åçã«æ±ã£ãŠãããŸãã
èªèšŒã»èªå¯ (repoze.who / TGAuthMetadata)
ãŠãŒã¶ãŒèªèšŒïŒãã°ã€ã³ç¶æ
ã®ç¢ºèªïŒãšèªå¯ïŒç¹å®ã®æäœãè¡ãæš©éããããã®ç¢ºèªïŒãæ±ããŸããæŽå²çã«ã¯ repoze.who
ãš repoze.what
ã䜿ãããŠããŸããããæè¿ã®ããŒãžã§ã³ã§ã¯ TurboGears èªèº«ã®èªèšŒã¡ã¿ããŒã¿ãããã€ã (TGAuthMetadata
) ã䜿ãããšãæšå¥šãããŠããŸããããã«ãããããã·ã³ãã«ã«èªèšŒã»èªå¯ã®ããžãã¯ãå®è£
ã§ããŸãã
ã³ãã³ãã©ã€ã³ããŒã« (Gearbox)
`gearbox` 㯠TurboGears ãããžã§ã¯ãã®ç®¡çã«äžå¯æ¬ ãªããŒã«ã§ãã
gearbox setup-app
: ã¢ããªã±ãŒã·ã§ã³ã®èšå®ãããŒã¿ããŒã¹ã®åæåãªã©ãgearbox serve
: éçºçšãµãŒããŒã®èµ·åãgearbox quickstart [project_name]
: æ°èŠãããžã§ã¯ãã®é圢ãäœæãgearbox migrate
: (Alembic ãšé£æºããŠ) ããŒã¿ããŒã¹ãã€ã°ã¬ãŒã·ã§ã³ãå®è¡ãgearbox tgshell
: ãããžã§ã¯ãã®ç°å¢ãèªã¿èŸŒãŸãã Python REPL ãèµ·åãã¢ãã«æäœã®ãã¹ããªã©ã«äŸ¿å©ã
ã€ã³ã¹ããŒã«ãšãããžã§ã¯ãäœæ ð ïž
TurboGears ãå§ããã®ã¯æ¯èŒçç°¡åã§ãã
åææ¡ä»¶
- Python (3.7 以éãæšå¥šãããŸã)
- pip (Python ããã±ãŒãžã€ã³ã¹ããŒã©ãŒ)
- ä»®æ³ç°å¢ (venv ã virtualenv ãªã©) ã®å©çšã匷ãæšå¥šããŸãã
ã€ã³ã¹ããŒã«
ãŸããä»®æ³ç°å¢ãäœæããã¢ã¯ãã£ããŒãããŸãã
# ä»®æ³ç°å¢ãäœæ (äŸ: myprojectenv ãšããåå)
python -m venv myprojectenv
# ä»®æ³ç°å¢ãã¢ã¯ãã£ããŒã
# Windows
myprojectenv\Scripts\activate
# macOS/Linux
source myprojectenv/bin/activate
次ã«ãTurboGears ãã€ã³ã¹ããŒã«ããŸãã
pip install tg.devtools
tg.devtools
ããã±ãŒãžã«ã¯ããã¬ãŒã ã¯ãŒã¯æ¬äœãšããããžã§ã¯ãäœæã«å¿
èŠãªããŒã« (Gearbox ãªã©) ãå«ãŸããŠããŸãã
ãããžã§ã¯ãäœæ
gearbox quickstart
ã³ãã³ãã䜿ã£ãŠãæ°ãããããžã§ã¯ãã®é圢ãäœæããŸãã
gearbox quickstart myapp
å®è¡ãããšããããžã§ã¯ãå (ããã§ã¯ `myapp`)ã䜿çšãããã³ãã¬ãŒããšã³ãžã³ (ããã©ã«ã㯠Kajiki)ãèªèšŒã»èªå¯ã®æç¡ãªã©ã察話圢åŒã§è³ªåãããŸããéžæã«å¿ããŠãå¿ èŠãªèšå®ãã¡ã€ã«ããã£ã¬ã¯ããªæ§é ãèªåçæãããŸãã
äž»ãªãã£ã¬ã¯ããªæ§é ã¯ä»¥äžã®ããã«ãªããŸãã
myapp/
âââ MANIFEST.in
âââ README.rst
âââ development.ini # éçºçšèšå®ãã¡ã€ã«
âââ myapp/ # ã¡ã€ã³ã®ã¢ããªã±ãŒã·ã§ã³ããã±ãŒãž
â âââ __init__.py
â âââ config/ # èšå®é¢é£ (environment.py, app_cfg.py, auth.py, ...)
â â âââ ...
â âââ controllers/ # ã³ã³ãããŒã©ãŒ (root.py, error.py, ...)
â â âââ ...
â âââ lib/ # ãã«ããŒé¢æ°ãªã© (base.py, helpers.py, ...)
â â âââ ...
â âââ model/ # ã¢ãã«å®çŸ© (__init__.py, models.py, ...)
â â âââ ...
â âââ public/ # éçãã¡ã€ã« (CSS, JavaScript, ç»åãªã©)
â â âââ ...
â âââ templates/ # ãã³ãã¬ãŒããã¡ã€ã« (index.xhtml, layout.xhtml, ...)
â â âââ ...
â âââ tests/ # ãã¹ãã³ãŒã
â â âââ ...
â âââ websetup/ # åæããŒã¿æå
¥ãªã© (bootstrap.py)
â âââ ...
âââ myapp.egg-info/ # ããã±ãŒãžæ
å ±
âââ production.ini # æ¬çªçšèšå®ãã¡ã€ã« (ãã³ãã¬ãŒã)
âââ setup.cfg
âââ setup.py # ããã±ãŒãžã³ã°èšå®
âââ test.ini # ãã¹ãçšèšå®ãã¡ã€ã«
äŸåé¢ä¿ã®ã€ã³ã¹ããŒã«ãšèšå®
ãããžã§ã¯ããã£ã¬ã¯ããªã«ç§»åããäŸåé¢ä¿ãã€ã³ã¹ããŒã«ããŸãã
cd myapp
pip install -e .
次ã«ãã¢ããªã±ãŒã·ã§ã³ã®åæèšå®ïŒããŒã¿ããŒã¹ããŒãã«ã®äœæãªã©ïŒãè¡ããŸãã
gearbox setup-app -c development.ini
-c development.ini
ã¯ãéçºçšã®èšå®ãã¡ã€ã«ã䜿çšããããšãæå®ããŸãã
éçºãµãŒããŒã®èµ·å
以äžã®ã³ãã³ãã§éçºãµãŒããŒãèµ·åããŸãã
gearbox serve -c development.ini --reload
--reload
ãªãã·ã§ã³ãä»ãããšãã³ãŒããå€æŽããéã«èªåçã«ãµãŒããŒãåèµ·åããããããéçºäžã¯äŸ¿å©ã§ãã
ããã©ã«ãã§ã¯ http://localhost:8080
ã§ã¢ã¯ã»ã¹ã§ããŸãããã©ãŠã¶ã§éããšãTurboGears ã®ãŠã§ã«ã«ã ããŒãžã衚瀺ãããã¯ãã§ããð
ç°¡åãªã¢ããªã±ãŒã·ã§ã³äœæäŸïŒHello World ãè¶ ã㊠ð
ããã©ã«ãã®ãããžã§ã¯ãã«ã¯æ¢ã«åºæ¬çãªã«ãŒãã£ã³ã°ãšãã³ãã¬ãŒããå«ãŸããŠããŸãããå°ãå€æŽãå ããŠã¿ãŸãããã
1. æ°ããããŒãžã®è¿œå
myapp/controllers/root.py
ãç·šéããŠãæ°ããã¢ã¯ã·ã§ã³ã¡ãœãããè¿œå ããŸãã
# myapp/controllers/root.py
from tg import expose
# ... (æ¢åã®importæ) ...
class RootController:
# ... (æ¢åã® index, about ã¡ãœãããªã©) ...
@expose('myapp.templates.hello') # æ°ãããã³ãã¬ãŒããæå®
def hello(self, person=None): # URLãã©ã¡ãŒã¿ãåãåã (äŸ: /hello?person=World)
"""Greets the user."""
greeting = f"ããã«ã¡ã¯ã{person or 'ã²ã¹ã'} ããïŒ"
return dict(page='hello', greeting=greeting) # ãã³ãã¬ãŒãã«å€æ°ãæž¡ã
ããã§ã¯ /hello
ãšãã URL ã«ã¢ã¯ã»ã¹ããããã® hello
ã¡ãœãããè¿œå ããŸãããperson
ãšãã URL ãã©ã¡ãŒã¿ãåãåããããã䜿ã£ãŠæšæ¶æãçæãããã³ãã¬ãŒãã«æž¡ããŠããŸãã
2. ãã³ãã¬ãŒãã®äœæ
myapp/templates/
ãã£ã¬ã¯ããªã«ãäžã§æå®ãã hello.xhtml
ãšãããã¡ã€ã«ãäœæããŸãã
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:layout="'layout.xhtml'"> <!-- layout.xhtml ãç¶æ¿ -->
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
<title>ãæšæ¶ããŒãž</title>
</head>
<body>
<div class="container">
<h2 class="title is-4">ãæšæ¶</h2>
<p class="notification is-success">${greeting}</p> <!-- ã³ã³ãããŒã©ãŒããæž¡ããã greeting å€æ°ã衚瀺 -->
<p>ããã¯æ°ããããŒãžã§ãã</p>
<a href="${tg.url('/?name=TurboGears')}">ãããããŒãžãž</a> <!-- URLçæãã«ããŒã®äŸ -->
</div>
</body>
</html>
py:layout="'layout.xhtml'"
ã§ãå
±éã¬ã€ã¢ãŠã (ããããŒãããã¿ãŒãªã©) ãå®çŸ©ãã layout.xhtml
ãç¶æ¿ããŠããŸããã³ã³ãããŒã©ãŒããæž¡ããã greeting
å€æ°ã ${greeting}
ã®ããã«ããŠè¡šç€ºããŠããŸãã
3. åäœç¢ºèª
éçºãµãŒããŒãèµ·åããŠããç¶æ ã§ããã©ãŠã¶ã§ä»¥äžã® URL ã«ã¢ã¯ã»ã¹ããŸãã
http://localhost:8080/hello
â “ããã«ã¡ã¯ãã²ã¹ã ãã ãšè¡šç€ºãããã¯ãã§ããhttp://localhost:8080/hello?person=TurboGears
â “ããã«ã¡ã¯ãTurboGears ãã ãšè¡šç€ºãããã¯ãã§ãã
ããã§ãæ°ããããŒãžãè¿œå ããã³ã³ãããŒã©ãŒãããã³ãã¬ãŒããžããŒã¿ãæž¡ãåºæ¬çãªæµãã確èªã§ããŸããã
TurboGears ã®ã¡ãªããã»ãã¡ãªãã ðð
TurboGears ãæ¡çšããéã®ã¡ãªãããšãã¡ãªãããæŽçããŠã¿ãŸãããã
ã¡ãªãã
- ãã«ã¹ã¿ãã¯ã®å©äŸ¿æ§: å¿ èŠãªæ©èœãäžéãæã£ãŠãããããã«éçºãå§ããããŸããèšå®ãããèŠçŽã®èãæ¹ãäžéšåãå ¥ããããŠããŸãã
- ã³ã³ããŒãã³ãã®æè»æ§: æšæºã³ã³ããŒãã³ãã¯åŒ·åã§ãããå¿ èŠã«å¿ããŠä»ã®ã©ã€ãã©ãªã«çœ®ãæããããç¡å¹åãããã§ããŸããç¹å®ã®æè¡ã¹ã¿ãã¯ã«çžããã«ããã§ãã
- å®çžŸã®ããã³ã³ããŒãã³ã: SQLAlchemy ã Routes ãªã©ãåºã䜿ããå®çžŸã®ããã©ã€ãã©ãªãããŒã¹ã«ããŠãããããå®å®æ§ãä¿¡é Œæ§ãæåŸ ã§ããŸãããããã®ã©ã€ãã©ãªã®ç¥èã¯ä»ã§ã掻ãããŸãã
- 匷åãªãŠã£ãžã§ããã·ã¹ãã : ToscaWidgets2 ã¯ãç¹ã«ãã©ãŒã ãå€çšãããããªç®¡çç»é¢ãªã©ã®éçºã«ãããŠçç£æ§ãåäžãããŸãã
- éçºããŒã«ã®å å®: `gearbox` ã³ãã³ãã©ã€ã³ããŒã«ã¯ãããžã§ã¯ã管çãå¹çåããŸãã
ãã¡ãªãã
- åŠç¿ã³ã¹ã: ãã«ã¹ã¿ãã¯ã§ãããããåŠç¿ãã¹ãã³ã³ããŒãã³ãïŒORM, ãã³ãã¬ãŒã, ãŠã£ãžã§ãããªã©ïŒãå€ããDjango ã Flask ã®ãããªç¹å®ã®é åã«ç¹åãããã¬ãŒã ã¯ãŒã¯ãšæ¯èŒãããšãåæã®åŠç¿æ²ç·ãããæ¥ãããããŸããã
- ã³ãã¥ããã£ãšãšã³ã·ã¹ãã : Django ã Flask ãšæ¯èŒãããšããŠãŒã¶ãŒã³ãã¥ããã£ã®èŠæš¡ã¯å°ãããæ¥æ¬èªã®æ å ±ããµãŒãããŒãã£è£œãã©ã°ã€ã³ã®æ°ã¯éãããåŸåããããŸããåé¡è§£æ±ºãæ å ±åéã§å°ãèŠåŽããå Žé¢ããããããããŸããã
- ããã©ãŒãã³ã¹: äžè¬çã«ãå€æ©èœãªãã«ã¹ã¿ãã¯ãã¬ãŒã ã¯ãŒã¯ã¯ããã€ã¯ããã¬ãŒã ã¯ãŒã¯ãšæ¯èŒãããšããªã¯ãšã¹ãåŠçã®ãªãŒããŒãããã倧ãããªãå¯èœæ§ããããŸãããã ããå€ãã®å Žåãã¢ããªã±ãŒã·ã§ã³ã®ããžãã¯ãããŒã¿ããŒã¹ã¢ã¯ã»ã¹ã®æ¹ãããã«ããã¯ã«ãªããŸãã
- ããã©ã«ããã³ãã¬ãŒããšã³ãžã³ (Kajiki/Genshi): XML ããŒã¹ã®ãã³ãã¬ãŒããšã³ãžã³ã¯ãä»ã®ãšã³ãžã³ (Jinja2, Mako) ã«æ £ããŠããéçºè ã«ãšã£ãŠã¯ãå°ãçããããšæãããããããããŸããããã ããèšå®ã§å€æŽå¯èœã§ãã
ä»ã® Python Web ãã¬ãŒã ã¯ãŒã¯ãšã®æ¯èŒ ð
TurboGears ããä»ã®äººæ° Python Web ãã¬ãŒã ã¯ãŒã¯ã§ãã Django ãš Flask ãšæ¯èŒããŠã¿ãŸãããã
ç¹åŸŽ | TurboGears | Django | Flask |
---|---|---|---|
åé¡ | ãã«ã¹ã¿ã㯠/ ã¡ã¬ãã¬ãŒã ã¯ãŒã¯ | ãã«ã¹ã¿ã㯠| ãã€ã¯ããã¬ãŒã ã¯ãŒã¯ |
åºæ¬ææ³ | æ¢åã®ãã¹ããªã³ã³ããŒãã³ããçµã¿åããããæè»æ§ãšãã«ã¹ã¿ãã¯ã®äž¡ç«ã | “Batteries Included” (å šéšå ¥ã)ãè¿ éãªéçºãDRYååã | ã·ã³ãã«ã§è»œéãã³ã¢ã¯æå°éãæ¡åŒµæ§ãé«ãã |
ã³ã³ããŒãã³ãéžæ | æ¯èŒçèªç±åºŠãé«ã (ORM, ãã³ãã¬ãŒãç) | ORM, ãã³ãã¬ãŒã, Admin ãªã©ã¯ã»ãŒåºå® (å€æŽã¯å¯èœã ãäžè¬çã§ã¯ãªã) | ã»ãŒå®å šã«èªç± (ORM, ãã³ãã¬ãŒãçã¯èªåã§éžæ) |
ORM | SQLAlchemy (æšæº) | Django ORM (æšæº) | ãªã (SQLAlchemy, Peewee ãªã©ãå¥éå°å ¥) |
ãã³ãã¬ãŒããšã³ãžã³ | Kajiki/Genshi (æšæº), Mako, Jinja2 ãªã© | Django Template Language (DTL) (æšæº), Jinja2 ãå©çšå¯ | Jinja2 (äºå®äžã®æšæº), Mako ãªã© |
管çç»é¢ | ãã©ã°ã€ã³ã§è¿œå å¯èœ (tgext.admin ãªã©) | Django Admin (æšæºã§åŒ·å) | Flask-Admin ãªã©ã®æ¡åŒµæ©èœã§è¿œå |
åŠç¿ã³ã¹ã | äžãé« (ã³ã³ããŒãã³ããå€ã) | äž (ç¬èªã®æŠå¿µãå€ã) | äœ (ã³ã¢ãå°ãã) |
ã³ãã¥ããã£/æ å ±é | å°ãäž | 倧 | 倧 |
é©ãããããžã§ã¯ãäŸ | äžã倧èŠæš¡ Web ã¢ããªã管çç»é¢ãæè»ãªæè¡éžæãå¿ èŠãªå Žåãæ¢åã³ã³ããŒãã³ãç¥èã掻ããããå Žå | 倧èŠæš¡ Web ã¢ããªãCMSããã¥ãŒã¹ãµã€ãã管çæ©èœãéèŠãªå Žåãè¿ éãªéçºãæ±ããããå Žå | å°èŠæš¡ã¢ããªãAPI ãµãŒããŒããããã¿ã€ãã³ã°ãç¹å®ã®æè¡ã¹ã¿ãã¯ã«ãã ããããå ŽåãåŠç¿ç®ç |
è£è¶³
- Django: éåžžã«å®æ床ãé«ããããã¥ã¡ã³ããã³ãã¥ããã£ãµããŒããå å®ããŠããŸããç¹ã«ç®¡çç»é¢æ©èœã¯åŒ·åã§ãããã ãããã¬ãŒã ã¯ãŒã¯ã®æµåã«åŸãéšåãå€ããªããŸãã
- Flask: éåžžã«ã·ã³ãã«ã§ãåŠç¿ãããããèªç±åºŠãé«ãã®ãç¹åŸŽã§ããå¿ èŠãªæ©èœãèªåã§éžãã§çµã¿åãããã¹ã¿ã€ã«ã§ããå°èŠæš¡ãªãããžã§ã¯ãã API éçºã«åããŠããŸãã
- TurboGears: Django ã®ãããªãã«ã¹ã¿ãã¯ã®å©äŸ¿æ§ãšãFlask ã®ãããªã³ã³ããŒãã³ãéžæã®æè»æ§ã䜵ãæã€ããšãç®æããŠããŸããSQLAlchemy ãã¡ã€ã³ã§äœ¿ããããããã㯠ToscaWidgets2 ã®ãããªãŠã£ãžã§ããã·ã¹ãã ã«é åãæããå Žåã«è¯ãéžæè¢ãšãªãåŸãŸãã
ãŸãšãïŒTurboGears ã®çŸåšãšæªæ¥ âš
TurboGears ã¯ãPython Web ãã¬ãŒã ã¯ãŒã¯ã®äžã§ããŠããŒã¯ãªããžã·ã§ã³ãå ããŠããŸãããã«ã¹ã¿ãã¯ã§ãããªããã³ã³ããŒãã³ãã®éžæè¢ãæ®ããšããã¢ãããŒãã¯ãéçºè ã«ãããã«äœ¿ãã䟿å©ãããšãåŸãã調æŽã§ããæè»æ§ãã®äž¡æ¹ãæäŸããŸãã
ç¹ã«ãSQLAlchemy ãäžå¿ãšããéçºãé²ãããå ŽåããToscaWidgets2 ã®ãããªåŒ·åãªãŠã£ãžã§ããã·ã¹ãã ã掻çšãããå Žåã«ã¯ãæåãªéžæè¢ãšãªãã§ããããæ¢åã® Python ã©ã€ãã©ãªã«é¢ããç¥èã掻ãããããç¹ãã¡ãªããã§ãã
äžæ¹ã§ãDjango ã Flask ãšæ¯èŒãããšã³ãã¥ããã£ã®èŠæš¡ãæ å ±ã®è±å¯ãã§ã¯å£ãé¢ããããŸããããããã³ã¢ãšãªãã³ã³ããŒãã³ãã¯å®å®ããŠãããéçºãç¶ç¶ãããŠããŸãããã¬ãŒã ã¯ãŒã¯ã®åºæ¬çãªã¢ãŒããã¯ãã£ã¯ TurboGears 2 ã®ç»å Žãã倧ããå€ãã£ãŠããŸããããPython ã®ããŒãžã§ã³ã¢ããè¿œåŸããäŸåã©ã€ãã©ãªã®æŽæ°ã现ããªæ¹åã¯ç¶ããããŠããŸãã
TurboGears ã¯ããã¹ãŠã®ãããžã§ã¯ãã«ãšã£ãŠæé©ãªéžæãšã¯éããŸãããããã®èšèšææ³ãç¹åŸŽããããžã§ã¯ãã®èŠä»¶ãããŒã ã®ã¹ãã«ã»ããã«åèŽããã°ãéåžžã«åŒ·åãªéçºããŒã«ãšãªãåŸãŸããããããªãããæè»æ§ãšçç£æ§ã®ãã©ã³ã¹ãåãã Python Web ãã¬ãŒã ã¯ãŒã¯ãæ¢ããŠãããªããTurboGears ãè©ŠããŠã¿ã䟡å€ã¯ååã«ããã§ããããð
èå³ãæã£ãæ¹ã¯ããã²å
¬åŒããã¥ã¡ã³ããåç
§ããå®éã« gearbox quickstart
ããå§ããŠã¿ãŠãã ããïŒ
ã³ã¡ã³ã