Its a declarative layer on top of SQLAlchemy a'la ActiveMapper (and
apparently "heavily inspired by ActiveMapper" according to the source).
It feels much more like SQLObject than ActiveMapper, has documentation,
and examples. In all respects, it seems like an excellent replacement
for ActiveMapper (and SQLObject, for that matter).
Also, the web site specifically mentions that it was built with
TurboGears in mind, and even includes an example for providing an
identity model for turbogears. Very exciting news, and I have already
contacted the author about the possibility of supplanting ActiveMapper
as the recommended declarative layer for SQLAlchemy.
Check it out, and I hope I didn't steal the author's thunder :)
--
Jonathan LaCour
http://cleverdevil.org
With TurboEntity work with tg-admin sql create
~and~
Can the author provide better documentation on the use of "select"
queries? IE select(id>50 and id<100)
Otherwise, looks great.
Thanks!
-chris
I'm not 100% sure but I'd be surprised if it didn't.
> Can the author provide better documentation on the use of "select"
> queries? IE select(id>50 and id<100)
Syntax is the same as standard sqlalchemy. The select is the same as
used in ActiveMapper and assign_mapper:
TableName.select(and_(TableName.c.id > 50, TableName.c.id < 100))
The website says that "automatic table creation works as normal."
This looks intriguing- I think I'll use it to make the switch to SQLAlchemy.
>
> For those of you who haven't seen yet:
>
> http://turboentity.ematia.de/
>
> Its a declarative layer on top of SQLAlchemy a'la ActiveMapper (and
> apparently "heavily inspired by ActiveMapper" according to the
> source).
> It feels much more like SQLObject than ActiveMapper, has
> documentation,
> and examples. In all respects, it seems like an excellent replacement
> for ActiveMapper (and SQLObject, for that matter).
Sounds like a good project, though I haven't looked at the details.
There's certainly a lot that can be done in that area, and the
featurelist is good.
> Also, the web site specifically mentions that it was built with
> TurboGears in mind, and even includes an example for providing an
> identity model for turbogears. Very exciting news, and I have already
> contacted the author about the possibility of supplanting ActiveMapper
> as the recommended declarative layer for SQLAlchemy.
Shh... we've got a book coming out in a few days that has a chapter
on using ActiveMapper ;)
Kevin
Till now we have three candidates for default SA:
1. ActiveMapper
2. plain SA definitions
3. TurboEntity
Lee McFadden has checked in [1997] to replace ActiveMapper with plain
SA definitions.
Though plain SA makes SA users feel comfortable that they can take full
advantage of SA with turbogears, it doen't make sense for sqlobject
users that they could do the same thing with half size of code.
Though to use 'turboentity' class to specify the 'tablename' doesn't
make sense to me,
it did a good job for support 'Self-referential' field that SQLObject
did not (without magic
)
Here's a list of how TurboEntity, SQLObject, Active Mapper specify
their table name:
TurboEntity:
class turboentity:
tablename = "tg_user"
SQLObject:
class sqlmeta:
table = "tg_user"
Active Mapper:
class mapping:
__table__ = "tg_user"
1. Yes, "tg-admin sql create" does work
(see http://turboentity.ematia.de/examples.html#s3 )
2. Select queries work exactly like the way they do
in ActiveMapper or plain SQLAlchemy. You can
read a lot about that at http://www.sqlalchemy.org/docs/
Daniel
I'm not fully happy with that choice, either. I chose it because I
don't think that it will cause any naming conflicts (as eg.
"settings" possibly could).
import sqlalchemy
from turboentity import *
from turboentity import objectstore
metadata = sqlalchemy.BoundMetaData("sqlite:///:memory:", True)
class Employee (Entity):
name = Column(Unicode(30))
class Engineer (Employee):
engineer_info = Column(Unicode(60))
class Marketer (Employee):
marketer_info = Column(Unicode(60))
create_all()
worker = Employee(name="Some Worker")
engineer = Engineer(name="Joe Engineer", engineer_info="joe's an
engineer")
marketer = Marketer(name="Pete Marketer", marketer_info="pete's a
marketer")
objectstore.flush()
objectstore.clear()
print Employee.get_by(Employee.c.name.like("Joe%")).name
print Employee.get_by(Employee.c.name.like("%Worker")).name
print Employee.get_by(Employee.c.name.like("Joe%")).engineer_info
print type(Employee.get_by(Employee.c.name.like("Pete%"))).__name__
---------------- 8< ----------------
I just found that there is a problem with inheritance
and relationships. I'm sure it worked before, I'll
investigate that soon.
Daniel
I tried to learn TurboEntity by porting simpleblog-part-2 to
TurboEntity
(porting simpleblog-part-1 is a pretty nice experience)
http://www.splee.co.uk/2006/10/20/simpleblog-part-2/
I've meet some problems:
1. How to use OneToMany map for Post-Comments relationship?
2. how to make backref work?
Without document It seems not that obvious.
Can we have a documentation sprint at PyCon - I know that much will have
improved by then, but I can bring a unique ignorance to the party to
help try and focus improvement where they will do most good.
Documentation is never finished ...
regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://holdenweb.blogspot.com
Recent Ramblings http://del.icio.us/steve.holden
ie.
class Post (Entity):
# properties here...
comments = OneToMany("Comment")
class Comment (Entity):
# properties here...
post = ManyToOne("Post")
You might want to specify backrefs, if you'd have more
one-to-many-relationships between Post and Comments, like
this:
class Post (Entity):
# properties here...
comments = OneToMany("Comment", backref="post")
class Comment (Entity):
# properties here...
post = ManyToOne("Post", backref="comments")
details here:
http://turboentity.ematia.de/docs.html#s3
Daniel
Thanks Daniel, I've made the simpleblog-part-1/part-2 porting to
turboentity, turboentity saved lots of code indeed.
Here's the Turboentity version of Simpleblog:
Simpleblog I
http://inet6.blogspot.com/2006/10/turboentity-simpleblog.html
Simpleblog II
http://inet6.blogspot.com/2006/11/turboentity-simpleblog.html
Most of the text looks cryptic to me (I'm german),
still the source code looks nice, thank you.
If you decide to use TurboEntity, I think I could be persuaded to
create a second downloadble appendix to cover that too. ;)
Persuading, right here! Twist, twist. ;)
Iain
class Post(Entity):
tags = ManyToMany('Tag')
class Tag(Entity):
posts = ManyToMany('Post')
Besides that, its still the best of breed choice for me.
----
Fred
>> Shh... we've got a book coming out in a few days that has a chapter
>> on using ActiveMapper ;)
>
> If you decide to use TurboEntity, I think I could be persuaded to
> create a second downloadble appendix to cover that too. ;)
Expect an announcement in the next few weeks about TurboEntity and
ActiveMapper joining forces. We are in active talks, and the end
result will likely be slightly different than what is available now.
Any chance that this "end result" will include something like Rails' "Acts"?
--
Tim Lesher <tle...@gmail.com>
Got an explanation for this? My google-fu is lacking.
I'm guessing it is a reference to the various "acts_as_*" plugins that
make it relatively easy to add row metadata (tags, voting, commenting,
etc) to your model.
In looking at it, TG could go one step further with a
widgets-and-decorator combo. The idea would be that any acts_as_*
plugin comes with some widgets and a decorator that allow the following
to make the change from non-voteable to voteable:
Original:
@expose(template)
def entries(self):
return dict(entries=model.entries.select(), entry_widget=mywidget)
@acts_as_voteable(mywidget, voteable.vote_widget)
@expose(template)
def entries(self):
...
Same for commenting, tagging, and anything else you might want to do.
I've had this idea sitting in the back of my head for a while, it
probably needs some fleshing out before it will work, but I think the
"you can make stuff voteable/taggable/etc with just a decorator and
some widgets" idea is a solid one.
-Adam
I took a look at Agile Rails book.
Besides the relationship between tables(OneToMany, ManyToMany...etc),
"acts_as_*" are the metadata(such as tablename is the metadata for sql
table, but acts_as_* are the metadata for model) for ActiveRecord
(rails ORM), which add an predefined set of methods to manipulate the
model.
For example, add a line to specify "acts_as_list" in model's metadata
could put results in order and act as a list;
"acts_as_tree" add some methods to play model like the tree structure.
SQLAlchemy/TurboEntity didn't have such stuff currently, but its not a
hard thing to warp a method to access SQLAlchemy/TurboEntity model in
native python code.
--
Fred
That sounds great, I really appreciate the work you guys are putting in
on the SA front. I left TG because of SO!
I wonder will there be an oppertunity to request some features? There
are bits of SO that I really liked that I miss, but I don't want to
sound whine-y :-)
Cheers
-Rob
>> Expect an announcement in the next few weeks about TurboEntity and
>> ActiveMapper joining forces. We are in active talks, and the end
>> result will likely be slightly different than what is available now.
>
> Any chance that this "end result" will include something like Rails'
> "Acts"?
We are looking at other such projects for inspiration to be sure. I
have used Rails' ActiveRecord a bit, and definitely found some things
there that are inspiring, and some things that aren't so inspiring.
And we are definitely open to suggestions. At this point there are
three of us with three different code bases with three slightly
different APIs. We are discussing any and every idea, and all of our
different approaches to the same problem. We welcome any ideas that
you may have!
It's a bit more than metadata. If you go back to the original
definition of the "active record" pattern (not the ActiveRecord
implemention in rails), it's all about encapsulating both data and
logic.
In practical terms, an "Act" adds metadata, domain logic, and
rendering logic (and customization hooks) to an object in a single
line of code, in a way that's easy to extend and easy to predict
(reducing interoperability issues).
For example, taking the "taggable" example, making an object
definition "taggable" would add not only the data columns and relation
tables to store tags, but it also would add methods like tag() and
untag() to the object itself. Votable might add (using SQLObject
notation) methods like vote(self, voter, vote_amount),
_get_avg_vote(self), _get_num_votes(self), _get_voters(self), etc.
> In looking at it, TG could go one step further with a
> widgets-and-decorator combo. The idea would be that any acts_as_*
> plugin comes with some widgets and a decorator that allow the following
> to make the change from non-voteable to voteable:
>
> Original:
> @expose(template)
> def entries(self):
> return dict(entries=model.entries.select(), entry_widget=mywidget)
>
> @acts_as_voteable(mywidget, voteable.vote_widget)
> @expose(template)
> def entries(self):
> ...
>
I'm not sure what purpose the decorator serves in your example. I
think the voteable object be enough to bring the appropriate widgets
along.
I haven't dug too deeply into the Ruby magic that implements Act, but
I believe that their approach is aggregation-based rather than
inheritance-based. It seems that one way to get this behavior would
be making TurboEntity support MI, but that has the usual set of
issues.
--
Tim Lesher <tle...@gmail.com>
> And we are definitely open to suggestions. At this point there are
> three of us with three different code bases with three slightly
> different APIs. We are discussing any and every idea, and all of our
> different approaches to the same problem. We welcome any ideas that
> you may have!
I'd like to see migrate come along with this project.
http://erosson.com/migrate/docs/
To provide extra methods to implement "act_as" function,
I wonder if it's possible to inherit "Entity" class rather than declare
"act_as" in metadata?
For example:
class Book (List): # declare in class, multiple inheritance possible
class turboentity:
tablename = "book"
rather than:
class Book (Entity):
class turboentity:
tablename = "book"
act_as = "List" # declare "act_as" in metadata
----
Fred
> To provide extra methods to implement "act_as" function,
> I wonder if it's possible to inherit "Entity" class rather than declare
> "act_as" in metadata?
>
> For example:
>
> class Book (List): # declare in class, multiple inheritance possible
> class turboentity:
> tablename = "book"
>
> rather than:
>
> class Book (Entity):
> class turboentity:
> tablename = "book"
> act_as = "List" # declare "act_as" in metadata
Personally I prefer the second option. It is more readable and lets your
intentions clearer.
--
Jorge Godoy <jgo...@gmail.com>
Rails uses Ruby mixins for this, which do end up looking a lot like
the above approach, but that's the standard Ruby idiom (since Ruby
doesn't support multiple inheritance).
I'd very slightly prefer a MI approach (assuming the usual issues with
MI can be worked around), if for no other reason than it's more
idiomatic in Python, and it's more discoverable and explorable from an
interactive shell (one of my complaints with SQLObject right now).
--
Tim Lesher <tle...@gmail.com>