From: Winston W. <win...@ca...> - 2005-03-10 23:03:29
|
I absolutely agree with your comments at the bottom about the state of web frameworks with python. It's not clear to me how to organize it to make it happen though, other than to keep stating it until everyone agrees. Especially, I wish we had more Webware releases. I suppose I could just do it myself, but I feel I don't really know enough yet. -ww On Mar 10, 2005, at 2:38 PM, Olivier FAVRE-SIMON wrote: > > For what it's worth I'm happy to share my way to use Cheetah with > Webware. Comments are welcome. > > > Starting with some facts: > > 1. The only way to have powerfull but well-structured Cheetah > templates is to use inheritance (#extends). > > 2. The only way to have FormKit (or any other form kit that rely on > Webware actions) whitout manually tweaking original source code is to > inherit from WebKit.Page > > 3. Cheetah.Template and WebKit.Page do not mix well (at least in > current versions) > > 4. I don't like the "inheritance" approach described in the Cheetah > User's Guide: I'm not a templar of the MVC church but a class > hierarchy with logic and view classes being intermixed seems ugly and > quite to me: > > Template <--- SiteLogic.py <--- Site.tmpl/.py <--- PageLogic.py <--- > Page.tmpl/.py <--- SecurePageLogic.py <--- LoginPageLogic.py <--- > LoginPage.tmpl/.py > > > > So I came to this design: > > Since templates are single inheritance only (only one base class, with > Template at the root), and I don't want intermixed logic/view classes, > let's > *** have 2 class hierarchies: one for logic, one for views *** : > > > WebKit.Page <-------------------+---SitePage.py <------+------ Main.py > | > | > MiscUtils.Configurable <--+ +------ ... > other public pages > > | > > +------ SecurePage.py <-------+------ Login.py > > | > > +------ Music.py > > | > > +------ ... other > 'login required' pages > > SitePageView.tmpl <------+------ MainView.tmpl > | > +------ LoginView.tmpl > | > +------ MusicView.tmpl > > > Each Page in the site will instantiate the corresponding View as > self.tmpl in its __init__() method. > > The .py View has been previously generated from the .tmpl via "cheetah > compile" and a Makefile. > > The searchList is [self], so the template can access all attributes > the same way it's done in the documented "inheritance approach". > > > The SitePage class defines 2 methods that subclasses may override: > - get_data() to gather all page data (i.e. the controler / business > logic) : Obviously must be redefined because each page has a different > content > - write_html() to generate page content (i.e. the view) : Most a the > time the default is sufficient : write the HTML via str(self.tmpl) > > Because all pages are Webkit pages rather than Cheetah templates it is > possible to use FormKit for the Login page and let Webware actions > handle the form. > > > ==================================================== > class SitePage(Page, Configurable): > > def __init__(self): > > Page.__init__(self) > Configurable.__init__(self) > > from SitePageView import SitePageView > self.tmpl = SitePageView(searchList=[self]) > > def writeHTML(self): > > self.get_data() > self.write_html() > > def write_html(self): > > self.writeln(str(self.tmpl)) > > ### etc. other SitePage methods ### > > > ==================================================== > class SecurePage(SitePage): > > def __init__(self): > SitePage.__init__(self) > > def awake(self, trans): > SitePage.awake(self,trans) > # pseudo-code here: use session() + database query to > check login data > if ## session invalid / expired## : > trans.response().sendRedirect('Login') > > ### etc. other SecurePage methods ### > > > ==================================================== > class Login(FormKitMixIn, SecurePage): > > def __init__(self): > > SecurePage.__init__(self) > > f = self.form = > Form.Form(validators=[PasswordValidator(self)]) > > self.addForm( f ) > > f.addField( Fields.TextField('username', > [Validators.MinLength(5)])) > f.addField( Fields.PasswordField('password', > [Validators.NotEmpty()])) > f.addField( Fields.WebKitSubmitButton(name="submit", > label="Log in")) > > from LoginView import LoginView > self.tmpl = LoginView(searchList=[self]) > > def get_data(self): > > SecurePage.get_data(self) > > self.login_form_html = self.form.dump() > #login_form_html is a place holder for the whole form in > LoginView.tmpl > > if not self.form.isSuccessful() and self.form.error(): > # add form error msg > self.login_form_html = self.login_form_html + > '<p style="color:red;">%s</p>' % self.form.error() > > def actions(self): > """Form actions - standard WebKit stuff""" > return ['submit'] > > def submit(self): > """action for submit button : save user info and > redirect to requested page (default: Main) if login successful.""" > > if self.form.isSuccessful(): > self.session().setValue('user', self.userid) > self.session().setValue('username', > self.form.username) > > self.response().sendRedirect(self.request().field('page', 'Main')) > > ### etc. other Login methods ### > > ==================================================== > class Music(SecurePage): > > def __init__(self): > > SecurePage.__init__(self) > > from MusicView import MusicView > self.tmpl = MusicView(searchList=[self]) > > def get_data(self): > '''A simple pusic page for the example: display all > songs that starts with a given letter in a music files directory.''' > SecurePage.get_data(self) > self.letter = self.request().field('letter','A') > DIR = '/mnt/disk/music' > from string import upper > from path import path > d = path(DIR) > self.music_files = [i.name for i in d.listdir() if > upper(i.name).startswith(upper(self.letter))] > #music_files is a place holder for MusicView.tmpl, wich > will iterate (e.g. #for $f in $music_files) to display > > ### etc. other Music methods ### > > > > > > To make it short what is needed for a new page is: > > 1. Instantiate the correct view in __init__() > 2. Override get_data() to generate content > 3. Provide the template for the view > > > On the negative side, the views must have been previously generated > from the .tmpl via "cheetah compile"; I've not found a way to have a > servlet instantiated template being dynamically compiled when it > #extends another template. > > With the help of a little Makefile: > > VIEWS=SitePageView.py LoginView.py MusicView.py > > .SUFFIXES: .py .tmpl > > all: $(VIEWS) > > LoginView.tmpl: SitePageView.py > Login.py: LoginView.py > > MusicView.tmpl: SitePageView.py > Music.py: MusicView.py > > clean: > rm -f *.pyc > rm -f *.py.bak > rm -f $(VIEWS) > > .PHONY: all clean > > .tmpl.py: > @cheetah compile $< > > > > > > I've been using python for some time now, mainly for PyGTK desktop > GUI's or XMLRPC/SOAP web services, but for pure web development I'm > coming from a PHP/Smarty background. > > PHP is good for rapid prototyping but on the long-term it's all > spaghetti code with screens "pulling" the data from databases. Rails > is really cool but it's Ruby ;-) > > I'ts a pity for me to see that python (IMHO the best language whatever > the domain you're working in) has 10 or so web frameworks with as many > template engines. That's too many brainpower dissipated in duplicate > endeavours. PHP and Rails are strong because the whole community > agreed that choosing a "main" (in not single) framework was more > important than any technical argument/point of > view/limitation/whatever. > > If we want python to *really* make it on web servers (I mean as an > opensource initiative, not Zope), the only way to succeed is (by > priority order): > > 1. Stop/refrain from developping new features when the existing > codebase is so poorly documented. (Microsoft MFC and .NET are crap but > the documentation is really impressing and make it possible to start > from scratch in very little time) > > 2. Add many examples and a real tutorial. What I mean is that one must > not have to copy/paste from html pages to have a running tutorial > site. We should have say a webware-examples.tar.bz2: just unpack it in > some /opt or /var/www directory, tweak httpd.conf a little and it must > be running from scratch). > > 3. Clearly an non-ambiguously define which packages are prefered and > which are deprecated: e.g. Many people advocate SQLObject for > Rails-alike sites (which I agree), but nowhere is it clearly defined > that one must choose SQLObject over MiddleKit, say for new sites. e.g. > I completely failed to understand what UserKit is meant for and how to > use it; googling about it did not return valuable info or a good > example. > > 4. Release early release often: The only thing that stops me to > actually put big Webware sites on the corporate servers in the company > i'm working for is seeing that same 0.8.1 version for so long. I know > that development is still going on: I'm regularly updating my > development box from ano...@cv... webware module but > any serious management will throw me away if I ever speak of a CVS > version on a prod server (even a tiny one). > > Trust matters, and the best way to ensure trust is to *show* that > things evolve; knowing it is not sufficient. > > > > What we need is JOINING FORCES (and not only in Webware+Cheetah; other > web frameworks (heho Aquarium) have common needs/requirements: form > handling, session management, etc. > > > Regards. > > > OFS. > > _________________________________________ winston wolff - (646) 827-2242 - http://www.stratolab.com - learning by creating |