TurboGears, or why I chose it over Django and Ruby on Rails

105 views
Skip to first unread message

Sean Cazzell

unread,
Nov 5, 2005, 5:09:20 AM11/5/05
to turbo...@googlegroups.com
I thought it would be interesting to write down why I chose TurboGears
over Django and Ruby on Rails as a sort of counterpoint Tabo's post
here:

http://tabo.aurealsys.com/archives/2005/10/11/django-or-why-i-chose-it-over-turbogears-and-ruby-on-rails/

I'll throw this up on the web eventually, but I was thinking maybe some
here could offer their own reasons for choosing TG.

As a bit of background, I first started developing database backed
websites in 1996 using Perl CGI scripts and Mini-SQL. I eventually
moved on to mod_perl, using Mason and Template-toolkit.

A couple of years ago I got into PHP, excited about a ubiquitous and
fast replacement for CGI scripts. PHP is a fairly terrible programming
language, but if you want to distribute web software it is great because
everyone already has it on their web server. I co-authored a book on
PHP and wrote countless lines of PHP but I often found myself working
around PHP's limitations rather than writing useful code. (And lets face
it, it is so much more fun to write code in Python than PHP)

Then at the beginning of this year I decided it was time to move on.
Time to learn something new. I decided to take a look at Java, Ruby and
Python. I would not have guessed I would end up picking Python, but I
fell in love with the clarity of the syntax and the lack of endless
magical functionality*.

Having decided on Python I was a little disappointed that it seemed very
few people were using it for web development. The web frameworks that
were available were really URL to function mappers with perhaps a
template language thrown in. Nothing wrong with that, just far from a
full web development stack. I ended up using a simple python server
pages implementation for templates, wrote my own ORM for Postgres and
used SCGI for the application server.

And things were good. Sometimes I wished for a Rails-style development
environment in Python and occasionally something similar would come
along, but nothing that really provided a compelling reason to switch
from my homegrown web-stack.

Then I heard about Django - I checked it out, but they were just
beginning to write the documentation and didn't have any videos (ooohhh
shiny webcasts!). Shortly after that Kevin Dangoor launched TurboGears
(and in a show of marketing shrewdness did the shiny webcast thing). I
decided to take a good look at both to see if I could ditch my homegrown
web stack for one and free up more of my time to write actual useful
code.

TurboGears was still very much getting off the ground and the Django
guys were starting to get a lot of the docs complete so I decided to try
out Django first (also Rob Curley's talk on IT conversations had piqued
my interest). I spent about a week playing with Django and reading
through much of the source code. I even submitted a couple patches.
More recently I have spent a few days with TurboGears.

I want to start with a bit of a disclaimer. Both projects are a large
leap forward in Python web frameworks. Both are managed by very capable
developers with strange last names (Django: Adrian Holovaty, TG: Kevin
Dangoor). Both are worthy choices for your web framework.


I'll break down this comparison into four parts:

1. ORM layer
2. URL mapping
3. Templating
4. Other Stuff

ORM Layers

TurboGears uses SQLObject and SQLObject is better. Django's ORM isn't
terrible, but SQLObject gets more things right. Using strings for
foreign key references between tables instead of the real class is a big
one. It makes setting up complex relationships between tables possible.
Some may prefer Django's syntax for doing selects over SQLObject's
sqlbuilder, but I personally prefer the more pythonic sqlbuilder.

(If you are blessed with only needing very simple models you may never
notice the limitations of Django's ORM in which case this becomes a much
closer comparison.)


URL Mapping

This one has to go to Django. The regexp-based url mapping makes it
easy to have beautiful, clean URLs in your app and to map them to any
arbitrary function. Things like:

http://www.example.com/blog/my_slug_here/

You can do this sort of thing in TurboGears, it just isn't as easy.
TurboGears uses CherryPy for a front end which really prefers options to
be specified in get variables like

http://www.example.com/blog?slug=my_slug_here


Templating

When it comes to templating, I think there are two camps. One, take the
full power of a programming language and make it available in your
templates. The other is to implement a templating language that barely
does anything other than variable interpolation and then slowly add
features to it until it becomes a programming language in it's own
right. TurboGears has chosen the former and Django has chosen the
latter.

TurboGears uses Kid which lets you write templates in XHTML with little
embedded python if statements and for loops. You can embed full python
functions in a template if you want to, but they can't output anything
directly and it isn't recommended.

You do get the full power of python in your if clauses and for loops
which means you can do any sort of arbitrary comparison that you need.
Things like:

<p py:if="system() == 'Linux'">
Good for you!
</p>

You can also define custom template functions and tags that act as
reusable blocks of HTML and kid can translate your XHTML code to HTML
4.0 for you - it is really quite flexible. The Kid language spec is
here:

http://kid.lesscode.org/language.html

Django uses their own template language which has a cool inheritance
feature. You can define your own tags that hook into the template
parser to add functionality. Django also implements a feature similar
to Template-Toolkit's Stash that allows you to use dots for method
calls, dictionary lookups, etc. So if you have

foo['bar'].baz()

You can call it from your template like:

{{ foo.bar.baz }}

Cool! They have some basic functions like an if statement, but it can
only check if a variable is true, no comparisons. So you can do

{% if foo %}
Wow foo is true.
{% endif %}

But you can't do

{% if foo > 5 %}
This doesn't work
{% endif %}

If you want to do a comparison, you have to use ifequal

{% ifequal foo bar %}
wow foo is equal to bar
{% endifequal %}

They also have ifnotequal and I suppose it is a matter of time before
someone implements ifgreaterthan, iflessthan and maybe even
ifgreaterthanorequalto, but this just seems silly to me.

If you are a big template minimalist you may prefer Django's approach,
but as soon as you want to do something slightly advanced like see if
one variable is greater than another your head is going to explode.

You could use another template system with Django, but a lot of the
things that make Django so nice like generic views and the built in
admin depend on the default template system.


Other Stuff

TurboGears is a bit newer. Django has a bit more thorough documentation
at the moment. TurboGears has built-in support for Ajax - you can use
the same controller methods for generating HTML and dumping out JSON.

Django has some features that are still in development on the TurboGears
side, notably a web interface to your model objects and full form
handling. But these things are not so hard to develop. The areas where
Django is lacking (ORM and templating) will not be as easy to fix.

It is true that TurboGears is made up of separate projects but I don't
think you can really "feel the glue" - maybe you can still smell it, but
it appears to be drying very quickly.


(*) When I was writing lots of Perl code I always had this vision of
Larry Wall and crew talking about Perl features like: "We must have a
magical loop variable" - "Yes, but what shall we call it?" - "Why $_ of
course! Unless it is an array, in which case it is @_!" - "Perfect!" I
should mention that I loved Perl and still have a certain fondness for
it and will leave all this Python nonsense behind the second Perl 6 is
done (just kidding ... we'll all be one big happy family on the Parrot
VM, right?!)




Sean Cazzell

Kevin Dangoor

unread,
Nov 5, 2005, 9:16:19 AM11/5/05
to turbo...@googlegroups.com
Hi Sean,

Thanks for writing this up! This kind of posting is good for showing
off our strengths and weaknesses here...

On 11/5/05, Sean Cazzell <seanc...@gmail.com> wrote:
> URL Mapping
>
> This one has to go to Django. The regexp-based url mapping makes it
> easy to have beautiful, clean URLs in your app and to map them to any
> arbitrary function. Things like:
>
> http://www.example.com/blog/my_slug_here/
>
> You can do this sort of thing in TurboGears, it just isn't as easy.
> TurboGears uses CherryPy for a front end which really prefers options to
> be specified in get variables like
>
> http://www.example.com/blog?slug=my_slug_here

People don't realize this, but CherryPy's system is a lot more
flexible than people give it credit for, and I like how CP does not
require a separate configuration for URLs. Your example here can be
handled fairly simply:

class Blog:
@turbogears.expose()
def default(self, slug):
...do something...

class Root(controllers.Root):
blog = Blog()

Also, CP 2.2 is going to add back positional parameters handling for
methods. There's a ticket open to do this in TurboGears, and I may
just do that as an interim measure until CP 2.2 is out. So, that adds
this option:

class Root(controllers.Root):
@turbogears.expose()
def blog(self, slug):
...do something...

This would actually allow either of these URLs to work:
/blog/slug

/blog?slug=slug

Kevin

modmans2ndcoming

unread,
Nov 5, 2005, 9:55:04 AM11/5/05
to TurboGears
Can I as why Root is inheriting from itself?

I saw this in the Tutorial (I think) and tried it out but I got an
error about controllers.Root not existing.

Kevin Dangoor

unread,
Nov 5, 2005, 10:00:36 AM11/5/05
to turbo...@googlegroups.com
On 11/5/05, modmans2ndcoming <jerem...@gmail.com> wrote:
>
> Can I as why Root is inheriting from itself?

from turbogears import controllers

class Root(controllers.Root):
pass

There was actually a proposal to change the name to RootController,
which I think I'll do because it's a bit clearer.

turbogears.controllers.Root is used to help find the root of applications.

Kevin

Sean Cazzell

unread,
Nov 5, 2005, 4:12:02 PM11/5/05
to turbo...@googlegroups.com
On Sat, 2005-11-05 at 09:16 -0500, Kevin Dangoor wrote:
> People don't realize this, but CherryPy's system is a lot more
> flexible than people give it credit for, and I like how CP does not
> require a separate configuration for URLs. Your example here can be
> handled fairly simply:
>
> class Blog:
> @turbogears.expose()
> def default(self, slug):
> ...do something...
>
> class Root(controllers.Root):
> blog = Blog()
>
> Also, CP 2.2 is going to add back positional parameters handling for
> methods. There's a ticket open to do this in TurboGears, and I may
> just do that as an interim measure until CP 2.2 is out. So, that adds
> this option:
>
> class Root(controllers.Root):
> @turbogears.expose()
> def blog(self, slug):
> ...do something...
>
> This would actually allow either of these URLs to work:
> /blog/slug
>
> /blog?slug=slug


Kevin, adding back positional params will be awesome. I know you can
currently use default, but you are going to have to create a separate
class for every exposed method or put some sort of dispatch logic into
your Root.default. I do agree that not having to maintain a separate
URL mapping file is nice and DRY.

Also turbogears.expose validators do not work with positional
parameters. I've toyed with various fixes to this - my initial thought
was to do introspection on the decorated method, but I think that breaks
when you have stacked decorators like

@turbogears.expose()
@require_group("Admin")
def blog(self, slug):
...

Maybe we could require that expose always decorate the method directly?
It makes things a little more fragile, but it would allow expose to
introspect the method it is decorating to get the names of positional
parameters.

We could allow validators to be specified as either a list or a dict,
but what if you want a url like:

http://www.example.com/blog/my_slug_here/?page=2

I'm not sure how you are going to specify the validator list for your
method:

@turbogears.expose()
def blog(self, slug, page=0)
... do something here ...

Maybe just have a separate positional_validators argument to expose?



Kind Regards,

Sean Cazzell

Michele Cella

unread,
Nov 5, 2005, 9:18:24 PM11/5/05
to TurboGears
Hi Sean,

Sean Cazzell wrote:
>
>
> Kevin, adding back positional params will be awesome. I know you can
> currently use default, but you are going to have to create a separate
> class for every exposed method or put some sort of dispatch logic into
> your Root.default. I do agree that not having to maintain a separate
> URL mapping file is nice and DRY.

You don't need a default method for every class, instead you can just
inherit your controller from this class:

cherrypy.lib.cptools.PositionalParametersAware

Take a look at ticket #73:

http://trac.turbogears.org/turbogears/ticket/73

I think that's the interim solution Kevin was talking about, It's a
simple fix so I hope it will make it to 0.9 on the base Controller
class, not only the Root one.

>
> Also turbogears.expose validators do not work with positional
> parameters. I've toyed with various fixes to this - my initial thought
> was to do introspection on the decorated method, but I think that breaks
> when you have stacked decorators like
>

Do they work with the above solution? Unfortunately I can't experiment
ATM.

Ciao
Michele

Sean Cazzell

unread,
Nov 6, 2005, 1:19:39 AM11/6/05
to turbo...@googlegroups.com
Michele,

Thanks for the pointer to that ticket.

PositionalParametersAware has a default method with some simple dispatch
logic. It doesn't work with turbogears.expose validators - they depend
on arguments being passed to the controller method by name so
turbogears.expose can match them up with the appropriate validator.

CherryPy 2.2 is going to allow positional arguments on all methods. I'm
not sure what their time frame for a 2.2 release is and how that will
work with Kevin's schedule for TG 1.0, but if we can get 2.2 in 1.0 that
would rock.

Beside this, we still need to fix the turbogears.expose validators to
work with positional arguments. One way is to require turbogears.expose
to be the first decorator on your controller methods - this way it can
use introspection to discover the names of your method's positional
args. Does anyone have any objections to mandating that
turbogears.expose be the first decorator?

The other solution is to have another argument to turbogears.expose -
something like positional_validators. But this is kind of ugly, IMHO.


Sean Cazzell

bon...@gmail.com

unread,
Nov 6, 2005, 1:26:16 AM11/6/05
to TurboGears

Sean Cazzell wrote:
> Beside this, we still need to fix the turbogears.expose validators to
> work with positional arguments. One way is to require turbogears.expose
> to be the first decorator on your controller methods - this way it can
> use introspection to discover the names of your method's positional
> args. Does anyone have any objections to mandating that
> turbogears.expose be the first decorator?
>
> The other solution is to have another argument to turbogears.expose -
> something like positional_validators. But this is kind of ugly, IMHO.
>
IMO, the easiest and the cleanest way is not have turbogear handle the
validating. It is unnatural and I found it to be useless if I want to
do anything that is useful. Just receive the params as kwargs(which
cherrypy would support no matter what change will be there) then
validator it using schema or whatever within the handler.

matthew clark

unread,
Nov 6, 2005, 1:41:01 AM11/6/05
to turbo...@googlegroups.com
This method would also be the most straight forward to extend for localization efforts, and uber-specialized needs.

I think too that it is intuaive, and makes for easy to read code.  Each page recieves the arguments, cleans the arguments, and processes the arguments.  Calls to those processors are right there inside the method.  Maybe a bit procedural, but simpler too.

matt

Steve Bergman

unread,
Nov 7, 2005, 1:14:05 PM11/7/05
to turbo...@googlegroups.com
bon...@gmail.com wrote:

>
>
>IMO, the easiest and the cleanest way is not have turbogear handle the
>validating. It is unnatural and I found it to be useless if I want to
>do anything that is useful. Just receive the params as kwargs(which
>cherrypy would support no matter what change will be there) then
>validator it using schema or whatever within the handler.
>
>
>
One thing that I would like to see is for the passing of args as **kwds
to become standard in TG. I write many, many lines of code that look like:

def functionname(
aaa='',
bbb='',
ccc=''
ddd=''
eee=''
fff=''
ggg=''):


followed further down by:

ret = dict(
aaa=aaa
bbb=bbb
ccc=ccc
ddd=ddd
eee=eee
fff=fff
ggg=ggg
)


followed a little further down, by:

Person = Person.get(PersonId)

ret = dict(
aaa=Person.aaa
bbb=Person.bbb
ccc=Person.ccc
ddd=Person.ddd
eee=Person.eee
fff=Person.fff
ggg=Person.ggg
)


If TG, SQLObject, and Formencode were all more dictionary oriented, much
of that tedious grunt work could be eliminated.

I have a project that I had originally written in php. Then I rewrote
it in mod_python. I am now finishing it up a rewrite to TG.

The mod_python version is smaller (and clearer) than the php version.
The TG version is smaller (and I think clearer) than the mod_python
version.

But the difference in size is not that dramatic. And when I look at my
TG code, I see a lot of lines devoted to tediously dealing with
individual attributes when I'd rather just take a dictionary, add or
modify a couple of the entries, pass it, and have it validated and
conditionally saved.

Just thought I'd mention this.

Thanks,
Steve Bergman

bon...@gmail.com

unread,
Nov 7, 2005, 1:22:03 PM11/7/05
to TurboGears
That is why I want to use the schema more and ask for more dict related
functionalities in FormEncode, SQLObject, TG. Coding in this style just
makes no sense to me. It looks cool for a quick 20 minutes wiki demo
but breaks down when I have lots of fields and lots of tables.

Leandro Lucarella

unread,
Nov 7, 2005, 1:25:01 PM11/7/05
to turbo...@googlegroups.com
Steve Bergman, el lunes 7 de noviembre a las 12:14 me escribiste:
> >IMO, the easiest and the cleanest way is not have turbogear handle the
> >validating. It is unnatural and I found it to be useless if I want to
> >do anything that is useful. Just receive the params as kwargs(which
> >cherrypy would support no matter what change will be there) then
> >validator it using schema or whatever within the handler.
>
> followed a little further down, by:
>
> Person = Person.get(PersonId)
>
> ret = dict(
> aaa=Person.aaa
> bbb=Person.bbb
> ccc=Person.ccc
> ddd=Person.ddd
> eee=Person.eee
> fff=Person.fff
> ggg=Person.ggg
> )

With svn's SQLObject now you can do:
ret = Person.get(PersonId).sqlmeta.asDict()

--
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
.------------------------------------------------------------------------,
\ GPG: 5F5A8D05 // F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05 /
'--------------------------------------------------------------------'
Pack and get dressed
before your father hears us,
before all hell breaks loose.

Ian Bicking

unread,
Nov 7, 2005, 1:37:30 PM11/7/05
to turbo...@googlegroups.com
Steve Bergman wrote:
>
> bon...@gmail.com wrote:
>
>>
>>
>> IMO, the easiest and the cleanest way is not have turbogear handle the
>> validating. It is unnatural and I found it to be useless if I want to
>> do anything that is useful. Just receive the params as kwargs(which
>> cherrypy would support no matter what change will be there) then
>> validator it using schema or whatever within the handler.
>>
>>
>>
> One thing that I would like to see is for the passing of args as **kwds
> to become standard in TG. I write many, many lines of code that look like:
>
> def functionname(
> aaa='',
> bbb='',
> ccc=''
> ddd=''
> eee=''
> fff=''
> ggg=''):

Of course, with this function definition you are really unpacking a
dictionary into local variables (a dictionary of which is available in
locals(), though I personally avoid using that). Or CherryPy is
unpacking for you. Anyway, there's a dictionary in there just waiting
to get out ;) Obviously (hopefully?) you can also use **fields in the
function signature.

FormEncode definitely prefers dictionaries -- it's not unpacking
anything. If you use variabledecode (which can be used with or without
FormEncode validators) then you can using naming conventions to get all
the values in a subdictionary. E.g., with keys like obj.aaa, obj.bbb,
etc, you'll get a dictionary in the variable obj. This can be used to
partition variables into a more cohesive set, with less issues of
unrelated variables leaking in, or having to rearrange the dictionary
that you get (popping keys and the like).


--
Ian Bicking / ia...@colorstudy.com / http://blog.ianbicking.org

Steve Bergman

unread,
Nov 7, 2005, 2:36:34 PM11/7/05
to turbo...@googlegroups.com
Leandro Lucarella wrote:

>With svn's SQLObject now you can do:
>ret = Person.get(PersonId).sqlmeta.asDict()
>
>
>
Yes. I've been looking forward to that feature's debut in TG. Can I
also pass a dictionary to SQLObject to set the attributes of an existing
or new object to the dictionaries values? It seems like I saw somewhere
that I can already do that?

If so, then by using Bonono's strategy, I would be able to do exactly
what I want. The only "tedious grunt work" I would have to do would be
to initialize my dict entries/attributes/fields once in my method for
putting up a form to get values for a new object. Everything else would
be just passing dictionaries and possible twiddling with an entry here
or there.

That would be exactly what I was looking for in TG. I looked at DJango,
etc. and decided that they looked too generalized. Django looked
great... if all you do is CMS. I wanted a generalized web "application"
framework. Not a web "CMS" framework. I want as much of the
flexibility of mod_python as I can retain, but with the framework
handling the wrote mechanical tedium.

BTW, bonono, I finally got to the reporting part of my app and tried out
the info in the link you provided me a while back to be able to do raw
SQL through SQLObject. Works great! But it did demonstrate to me how
I'd gotten used to the simplicity of SQLObject for doing simple DB
related things. (And it was a bit jarring having to switch gears even
insofar as what the fields db fields were named, e.g. "employee_phone"
vs "employeePhone".)

A fusion of the two ways of doing things into TG would be a match made
in heaven. The only problem being that I wouldn't have anything more to
complain about! ;-)

-Steve

bon...@gmail.com

unread,
Nov 7, 2005, 2:47:42 PM11/7/05
to TurboGears

Steve Bergman wrote:
> Yes. I've been looking forward to that feature's debut in TG. Can I
> also pass a dictionary to SQLObject to set the attributes of an existing
> or new object to the dictionaries values? It seems like I saw somewhere
> that I can already do that?
Using the .set(**dict) or something like that should do the trick

>
> BTW, bonono, I finally got to the reporting part of my app and tried out
> the info in the link you provided me a while back to be able to do raw
> SQL through SQLObject. Works great! But it did demonstrate to me how
> I'd gotten used to the simplicity of SQLObject for doing simple DB
> related things. (And it was a bit jarring having to switch gears even
> insofar as what the fields db fields were named, e.g. "employee_phone"
> vs "employeePhone".)
>
> A fusion of the two ways of doing things into TG would be a match made
> in heaven. The only problem being that I wouldn't have anything more to
> complain about! ;-)

My thought too(well not the complain part ;-p). I am walking between
them. Using the SQLBuilder for things of medium complexity and stored
procedure on the server for hardcore SQL. SQLObject by itself is great
for form filling and the like, including parent child.

Ian Bicking

unread,
Nov 7, 2005, 2:48:17 PM11/7/05
to turbo...@googlegroups.com
Steve Bergman wrote:
> BTW, bonono, I finally got to the reporting part of my app and tried out
> the info in the link you provided me a while back to be able to do raw
> SQL through SQLObject. Works great! But it did demonstrate to me how
> I'd gotten used to the simplicity of SQLObject for doing simple DB
> related things. (And it was a bit jarring having to switch gears even
> insofar as what the fields db fields were named, e.g. "employee_phone"
> vs "employeePhone".)

If you use Class.q.employeePhone, that should translate to
class.employee_phone in the SQL.

Steve Bergman

unread,
Nov 7, 2005, 3:14:49 PM11/7/05
to turbo...@googlegroups.com
Ian Bicking wrote:

> If you use Class.q.employeePhone, that should translate to
> class.employee_phone in the SQL.


Is that supposed to work in this context?

results = Timesheet._connection.queryAll("""SELECT
Client.q.clientName,

Project.q.projectDesc,

Timesheet.q.travelTime,

Timesheet.q.regularTime,

Timesheet.q.description,

TImesheet.q.internalNote
FROM
Timesheet,
Client,
Project
WHERE

timesheet.client_id = Client.id AND

timesheet.project_id = Project.id AND
date >=
'%s' AND
date <= '%s'
ORDER BY

client.client_name""" % (beginDate, endDate)
)

I'm getting an error saying that Client.q.clientName does not exist. Is
there a better way of doing this? Or did I get something wrong?


Ian Bicking

unread,
Nov 7, 2005, 3:15:32 PM11/7/05
to turbo...@googlegroups.com
Steve Bergman wrote:
>
> Ian Bicking wrote:
>
>> If you use Class.q.employeePhone, that should translate to
>> class.employee_phone in the SQL.
>
>
>
> Is that supposed to work in this context?

No, you have to use it with SQLBuilder syntax, like
queryAll(sqlbuilder.Select(
[Client.q.clientName, ...],
where=(Timesheet.q.clientID == Client.q.id, ...)))

Benoit Masson

unread,
Nov 7, 2005, 6:07:31 PM11/7/05
to turbo...@googlegroups.com
Hello,
If you werre about to have a website with turbogears how would you
handle statistics ? Are there special functions or API for that ?
Must we relly on apache or lighttp stats ?

Thanks

Steve Bergman

unread,
Nov 10, 2005, 12:42:47 PM11/10/05
to turbo...@googlegroups.com
bon...@gmail.com wrote:

>Steve Bergman wrote:
>
>
>>Yes. I've been looking forward to that feature's debut in TG. Can I
>>also pass a dictionary to SQLObject to set the attributes of an existing
>>or new object to the dictionaries values? It seems like I saw somewhere
>>that I can already do that?
>>
>>
>Using the .set(**dict) or something like that should do the trick
>
>
>
Thanks. That works just fine for updating a record.

I've converted everything in my app from using the TG validation
mechanism, to your method of passing all function arguments as **kw and
using schemas. Also, to use the .set method for updates.

I must say, you were right. I like this style. It feels more
Pythonic. ( I can almost hear it hissing. ;-P )

Hopefully with the next release I'll be able to retrieve an object's
attributes into a dictionary in just a single statement as Leandro was
kind enough to point out.

So, is there a way to create a *new* object and feed it a dictionary in
a concise way? I can't just create an empty object and then use .set
because, of course, it complains about missing attributes when I create
the object.

Also, the way I am doing things is to pass all function/method args in
**kw and setting allow_extra_fields and filter_extra_fields to True in
the schema. Any function arguments that don't go into the database just
get a dummy line in the schema so they don't get stripped prematurely.
Then, right before I actually add or update, I pop the extra values off
to avoid the object complaining about unexpected attributes when I update.

Does that sound like the most efficient way to do it?

Thanks,
Steve

bon...@gmail.com

unread,
Nov 10, 2005, 1:28:19 PM11/10/05
to TurboGears

Steve Bergman wrote:
> So, is there a way to create a *new* object and feed it a dictionary in
> a concise way? I can't just create an empty object and then use .set
> because, of course, it complains about missing attributes when I create
> the object.
I think you can do the same with the class method.

SO(**dict)
as it is the same as
SO(key1=a, key2=b)

>
> Also, the way I am doing things is to pass all function/method args in
> **kw and setting allow_extra_fields and filter_extra_fields to True in
> the schema. Any function arguments that don't go into the database just
> get a dummy line in the schema so they don't get stripped prematurely.
> Then, right before I actually add or update, I pop the extra values off
> to avoid the object complaining about unexpected attributes when I update.
>
> Does that sound like the most efficient way to do it?
>

If you have a schema that matches the database fields, you can :

d = dbSchema(allow_extra_fields=True,
filter_extra_fields=true).to_python(kw )
SO(**d) # if you want to add
so.set(**d) # if you want to update

The schema to_python function would filter out fields it doesn't know.

Personally, I just scrape the database metaclass to create such a
schema so I don't even need to define one line by line and any changes
to the database table definition would be retrieved.

Steve Bergman

unread,
Nov 10, 2005, 2:31:35 PM11/10/05
to turbo...@googlegroups.com
bon...@gmail.com wrote:

> I think you can do the same with the class method.
>
>SO(**dict)
>as it is the same as
>SO(key1=a, key2=b)
>
>

>If you have a schema that matches the database fields, you can :
>
>d = dbSchema(allow_extra_fields=True,
>filter_extra_fields=true).to_python(kw )
>SO(**d) # if you want to add
>so.set(**d) # if you want to update
>
>The schema to_python function would filter out fields it doesn't know.
>
>Personally, I just scrape the database metaclass to create such a
>schema so I don't even need to define one line by line and any changes
>to the database table definition would be retrieved.
>
>
Thank you. I'll try that out. In particular, it was bothering me
having separate validation definitions in the model and in the
controllers that would have to be kept in sync. Not very DRY.

Much appreciated!

-Steve

David Stanek

unread,
Nov 14, 2005, 2:06:19 PM11/14/05
to turbo...@googlegroups.com
Since I run TG behind Apache I let Apache handle writing the logs and I use awstats to get the pretty view.

-- David
Reply all
Reply to author
Forward
0 new messages