ลองใช้ pylons, tw.forms และ elixir ลองทำ application ง่ายๆ ตาม http://pylonsbook.com/alpha1/simplesite_tutorial ดูก็ดัดแปลงนิดหน่อยๆ เลยอย่างจะเขียนรวมกันไว้ที่เดียว. อาจจะดูมั่วๆ บ้างไว้มี version ต่อไปค่อย post อีกทีแล้วกัน.
pylons (20080818) นี้เลือกได้เลยว่าให้สร้าง code ที่ support mako และ sqlalchemy ได้เลย แต่จะใช้ elixir และ tw.forms ก็ต้องมาแก้นิดๆ หน่อย. เอา elixir ก่อนแล้วกัน.
แก้ lib/base.py:
from pylons.controllers import WSGIController
from pylons.templating import render_mako as render
import elixir # เพิ่มนี้เข้ามา
class BaseController(WSGIController):
def __call__(self, environ, start_response):
try:
return WSGIController.__call__(self, environ, start_response)
finally:
elixir.session.remove() # เพิ่มนี้เข้ามา
แก้ model/meta.py:
from sqlalchemy import MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
__all__ = ['Session', 'metadata']
engine = None
แก้ model/__init__.py:
import sqlalchemy as sa
from sqlalchemy import orm
from simple1.model import meta
import elixir
sm = orm.sessionmaker(autoflush=True, autocommit=True)
elixir.session = orm.scoped_session(sm)
elixir.options_defaults.update({ 'shortnames': True })
def init_model(engine):
elixir.metadata.bind = engine
from elixir import *
from entities import *
elixir.setup_all()
แล้วก็แก้ websetup.py:
"""Setup the simple1 application"""
import logging
from simple1.config.environment import load_environment
log = logging.getLogger(__name__)
def setup_app(command, conf, vars):
"""Place any commands to setup simple1 here"""
load_environment(conf.global_conf, conf.local_conf)
import elixir # ใส่ elixir ไปแทน
elixir.metadata.create_all(checkfirst=True) # บรรทัดนี้ด้วย
ส่วนที่ใส่ไปข้างบนนี้ไม่ขึ้นกับ app นะครับ ต่อไปก็เติม entity ใน model สักหน่อย ชื่อ Person ข้างในก็มีแค่ first name กับ last name
แก้ model/entities.py:
from elixir import *
class Person(Entity):
first_name = Field(String(1000))
last_name = Field(String(1000))
ว่าด้วยเรื่อง elixir ก็เกือบหมดแล้ว ที่เหลือก็อยู่ใน controller เลย. เพื่อที่จะสร้าง model ก็ลองสร้าง database เลยสั่ง
paster setup-app development.ini
ต่อด้วย tw.forms โดยทั่วไปแล้วพอหลังลง package ก็ลงแก้ config/middleware.py: แต่มันยาว ก็แค่เพิ่มอะไรไปนิดๆ หน่อยๆ
...
from tw.api import make_middleware # แก้ตรงนี้ เพิ่มเข้ามา
...
# แก้ตรงนี้
# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
app = make_middleware(app, {
'toscawidgets.framework' : 'pylons',
'toscawidgets.framework.default_view' : 'mako',
'toscawidgets.middleware.inject_resources' : True,
})
...
ว่าด้วยเรื่อง view (template)
แก้ lib/helpers.py
from webhelpers import *
from webhelpers.html.tags import *
from routes import url_for
from webhelpers.html import literal
from webhelpers.pylonslib import Flash as _Flash
from webhelpers import paginate
flash = _Flash()
สร้าง widgets ก่อนจะได้เขียน template สั้นๆ สร้าง widgets/person.py
from tw import forms
from tw.api import WidgetsList
forms.FormField.engine_name = 'mako'
class PersonForm(forms.TableForm):
class fields(WidgetsList):
first_name = forms.TextField()
last_name = forms.TextField()
submit = forms.SubmitButton(attrs = {'value': 'save'})
person_form = PersonForm(id = 'person_form')
สร้าง base template ใน template/base.html: ต่างจากใน tutorial นิดๆ ที่มี flash message ด้วย
## -*- coding: utf-8 -*-
${self.title()}
${self.head()}
${self.header()}
${self.tabs()}
${self.menu()}
${self.heading()}
${self.breadcrumbs()}
${self.flash_messages()}
${next.body()}
${self.footer()}
% if messages:
<ul id="flash-messages">
% for message in messages:
<li>${message}</li>
% endfor</ul>
% endif
Simple1
<a name="top"></a>
<h1>${c.heading or 'No Title'}</h1>
<a href="#top">Top ^</a>
แก้ template/person/list.html:
<h1 class="main">Person List</h1>
<ul id="titles">
% for person in c.paginator:
<li>${person.first_name} ${person.last_name}
[${h.link_to('view', h.url_for(controller='person', action='view', id=person.id))}]
[${h.link_to('edit', h.url_for(controller='person', action='edit', id=person.id))}]
[${h.link_to('delete', h.url_for(controller='person', action='delete', id=person.id), onclick="return confirm('Are you sure you want to delete #" + str(person.id) + "?');")}]</li>
% endfor</ul>
<a href="${h.url_for(controller='person', action='new', id=None)}">New person</a>
${parent.footer()}
แก้ template/person/new.html:
<h1 class="main">Add person</h1>
${h.literal(person_form(action=h.url_for(controller='person', action='create')))}
แก้ template/person/new.html:
<h1 class="main">Edit person info</h1>
${h.literal(person_form(action=h.url_for(controller='person', action='save')))}
<a href="${h.url_for(controller='person', action='list')}">All people</a>
| <a href="${h.url_for(controller='person', action='edit', id=c.person.id)}">Edit person</a>
| <a href="${h.url_for(controller='person', action='delete', id=c.person.id)}">Delete person</a>
${parent.footer()}
แก้ template/person/view.html:
View person
<h1>View person</h1>
${c.person.first_name}
${c.person.last_name}
<a href="${h.url_for(controller='person', action='list')}">All people</a>
| <a href="${h.url_for(controller='person', action='edit', id=c.person.id)}">Edit person</a>
| <a href="${h.url_for(controller='person', action='delete', id=c.person.id)}">Delete person</a>
${parent.footer()}
สุดท้ายแล้วมั้งก็สร้าง controller แก้ controller/person.py:
import logging
from pylons import request, response, session
from pylons import tmpl_context as c
from pylons.controllers.util import abort, redirect_to
from simple1.lib.base import BaseController, render
import simple1.model as model
from simple1.lib import helpers as h
log = logging.getLogger(__name__)
from simple1.widgets.person import person_form
from tw.mods.pylonshf import validate
from webhelpers import paginate
import elixir
from formencode import htmlfill
def get_person(id):
if id is None:
abort(404)
person = model.Person.query.get(int(id))
if person is None:
abort(404)
return person
class PersonController(BaseController):
def index(self):
return redirect_to(action='list')
def list(self):
page_number = request.params.get('page', 1)
people = model.Person.query.all()
c.paginator = paginate.Page(people, page = page_number)
return render('/person/list.html')
def new(self):
return render('/person/new.html')
@validate(form=person_form, error_handler='new')
def create(self):
if request.method != 'POST':
about(500)
person = model.Person()
for k,v in self.form_result.items():
setattr(person, k, v)
elixir.session.flush()
h.flash("added person")
return redirect_to(action='index')
def view(self, id):
c.person = model.Person.query.get(int(id))
return render('/person/view.html')
def delete(self, id=None):
person = get_person(id)
person.delete()
elixir.session.flush()
h.flash("deleted person")
#referer = request.headers.get('REFERER', '/')
#return redirect_to(referer)
return redirect_to(action='list')
def edit(self, id=None):
person = get_person(id)
return htmlfill.render(render('/person/edit.html'), person.to_dict())
@validate(form=person_form, error_handler='edit')
def save(self, id=None):
person = get_person(id)
for k,v in self.form_result.items():
setattr(person, k, v)
elixir.session.flush()
h.flash("edited person")
return redirect_to(action='view')
ดูอนาถๆ กลับมาอ่านทีหลังไม่รู้รู้เรื่องเปล่า
อ้างอิงเพิ่ม:
http://toscawidgets.org/documentation/tw.forms/tutorials/pylons_one.html
https://www.knowledgetap.com/hg/webhelpers/file/2eb9f423aafb/webhelpers/pylonslib.py