Re: [Repoze-dev] object graph traversal question
2009/11/12 F. Oliver Gathmann gathm...@cenix-bioscience.com: I guess I'm asking if there is a standard, bfg-approved way of avoiding artificial container model classes - or did I just not get it yet?! You can use ``*subpath`` (or any other name of your choice) to retrieve this match as-is, without invoking the traverser. \malthe ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] object graph traversal question
F. Oliver Gathmann wrote: Hello! Coming from Pylons, I'm a newbie to the object graph traversal world, so this question might be slightly misplaced (but hopefully a no-brainer for the bfg gurus...). I very much like the concept of looking up my model object before dispatching to a view that operates on it. However, what bothers me about the standard traversal algorithm is that, for a URL like /cars/beetle/wheels/front_left I have to promote the containers (cars and wheels) to first class citizens in my model (by defining CarContainer and WheelContainer classes that I can then instantiate and return as the context object from the parent's __getitem__), where in fact they are just collections held by their mutual parent model objects (the Root object in case of the cars collection - which is in itself artificial, but I'm willing to pay that price for traversability - and the Car object in case of the wheels collection). Great question. The short answer is yes, you have to define the intermediate artificial objects if you want to use traversal. There are number of ways to conceptualize this. The first way would be to not consider this a traversal problem at all and do it as you might in Pylons by registering a route that had static parts and dynamic parts: route name=wheel path=/cars/:type/wheels/:wheel view=.views.wheel_view/ This will do more or less what you expect, but your view will need to resolve the dynamic bits from your model. The paster template closest to this model is bfg_routesalchemy. Another way to do it would be to use *only* traversal and define an object graph: class Root(dict): def __getitem__(self, name): return self[name] class Cars(object): def __getitem__(self, name): use the rdb to find the car model and return a Car ... class Car(object): def __getitem__(self, name): use the rdb to find the part (such as a Wheel) and return it... class Wheel(object): # leaf node pass model_graph = Root({'cars':Cars()}) def get_root(request): return model_graph Then define a view like so: view view=.views.wheel_view for=.models.Wheel / Then the URL to a wheel model might be: /cars/beetle/front_wheel You can choose to inject a wheels collection in there too should you want, but since objects have a type in this setup, it's not strictly necessary. The paster template closest to this model is bfg_alchemy (or bfg_zodb but that uses ZODB rather than SQL). Those are the two sanest ways to do this. There's another mode that combines both traversal and url dispatch (routes), but I don't think it helps much here. Malthe suggested that you can also use request.subpath. This is the remainder of the path (as a tuple) when a traversal falls off the graph. Another (much cruder) way to getting this done would be to one root model and a single view and use request.subpath as a cue to that view about what needs to be done. You could of course have a cars model that resolved a car and a view against the car, then use the remainder of the subpath to figure out which part to show; dialing use of request.subpath up or down in length. I guess I'm asking if there is a standard, bfg-approved way of avoiding artificial container model classes - or did I just not get it yet?! No, you got it. - C ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] object graph traversal question
On 11/12/09 1:00 PM, Tim Hoffman wrote: Hi I have done some fairly extensive projects using traversal over a relational model and we did use intermediate container classes alot. Mainly because each major entity could have about 6 different classes of sub items that we needed to group into containers anyway I reverse engineered the entire relational model from the existing database and then autogenerated all of the intermediate classes. Quite easy to do. I was using storm as an orm over the top, which made things a lot easier Hmm... still, this feels like an artifact to me. Presumably, in most cases what you want to return when the URL asks for a collection of sub-items is the very collection you already defined in your ORM on the model object that is the current context (we are using SQLAlchemy, BTW). I cannot help but think that there should be a way to automatically return an adapted collection that supports further traversal if necessary... but I'm not sure of all the ramifications of that idea. Oliver T On Thu, Nov 12, 2009 at 7:43 PM, F. Oliver Gathmann gathm...@cenix-bioscience.com wrote: On 11/12/09 11:03 AM, Tim Hoffman wrote: Hi I suppose it doesn't really matter how you go, and quite possibly the deciding factor on why you might need the wheel container and car container classes will depend on how you access data, For instance if you use something like zodb you can put arbitrary entities inside other entities, (i.e someones/garage/beetle/frontleft) where as if you data is coming from a relational dbms the wheel container class may in fact represent the table of all possible wheels. and you are using the beetle car to determine which instances of wheels (wheels in the wheel table) that it owns. That's precisely where we are coming from (we have a big legacy DB to deal with). If you have a really rigid relation model with a finite set of levels then you may find you are creating arbitrary intermediate containers just so you can define how you access the data. in this case maybe routes may be a better alternative Where as arbirtratry depth trees where each node can contain arbitrary types (think of a filesystem containing many different file types or potentially any depth) really suit traversal as anything can probably be a container. Oh - and I had hoped to be able to ditch routes now that I have model graph traversal ;-). I'd say our relational model is neither rigid nor arbitrary - we are constantly making changes but of course we stay within the limits of our domain model. Just my 2c worth. I have to think some more about this, it seems - you 2c are much appreciated, thanks! Oliver On Thu, Nov 12, 2009 at 5:40 PM, F. Oliver Gathmann gathm...@cenix-bioscience.com wrote: Hello! Coming from Pylons, I'm a newbie to the object graph traversal world, so this question might be slightly misplaced (but hopefully a no-brainer for the bfg gurus...). I very much like the concept of looking up my model object before dispatching to a view that operates on it. However, what bothers me about the standard traversal algorithm is that, for a URL like /cars/beetle/wheels/front_left I have to promote the containers (cars and wheels) to first class citizens in my model (by defining CarContainer and WheelContainer classes that I can then instantiate and return as the context object from the parent's __getitem__), where in fact they are just collections held by their mutual parent model objects (the Root object in case of the cars collection - which is in itself artificial, but I'm willing to pay that price for traversability - and the Car object in case of the wheels collection). I guess I'm asking if there is a standard, bfg-approved way of avoiding artificial container model classes - or did I just not get it yet?! I'm very grateful for any hints and pointers you may have on this issue. Thanks, Oliver -- F. Oliver Gathmann, Ph.D. Director IT Unit Cenix BioScience GmbH Tatzberg 47 phone: +49 (351) 4173-136 D-01307 Dresden, Germany fax: +49 (351) 4173-109 - Sitz der Gesellschaft (Place of Business): Dresden Geschaeftsfuehrer (CEO): Dr. Christophe J. Echeverri Amtsgericht (Local Court): Dresden, HRB 19964 Ust-ID (VAT-No.): DE205824437 - ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev -- F. Oliver Gathmann, Ph.D. Director IT Unit Cenix BioScience GmbH Tatzberg 47 phone: +49 (351) 4173-136 D-01307 Dresden, Germany fax: +49 (351) 4173-109
Re: [Repoze-dev] object graph traversal question
On 11/12/09 1:20 PM, Tim Hoffman wrote: Hi On Thu, Nov 12, 2009 at 8:09 PM, F. Oliver Gathmann gathm...@cenix-bioscience.com wrote: Hmm... still, this feels like an artifact to me. Presumably, in most cases what you want to return when the URL asks for a collection of sub-items is the very collection you already defined in your ORM on the model object that is the current context Except if an entity has multiple sub collections you need to define a way of differentiating each sub collection from a traversal point of view If you want a listing of all the wheels then you need /garage/beetle/wheels Now that would return all of the wheels. Its up to you then if you want to directly traverse to front wheel either by /garage/beetle/front_wheel or /garage/beetle/wheels/front_wheel We might also have a collection of doors /garage/beetle/doors And as long as you don't name a door front_wheel you would be fine not traversing the wheel container. I definitely would not want to rely on my users *not* to call a door front_wheel ;-) It all comes down to how you would be identifying any particular child entity. Yes, that makes sense. (we are using SQLAlchemy, BTW). Never used that. I cannot help but think that there should be a way to automatically return an adapted collection that supports further traversal if necessary... but I'm not sure of all the ramifications of that idea. Yep you could definatley do that. However as I pointed out earlier if you have multiple sub collections you still need to identify the collection/adapter. In the case above wheels might be an adatper name (though I don't see the difference really between an adapter or container class. Neither in itself is persistent and an instance will only exist whilst traversing. That's a good point. I guess nobody would force me to keep the intermediary container classes *in* my model tree, either. Thanks for all these thoughtful comments; I think, slowly, a picture is emerging :-) Oliver On Thu, Nov 12, 2009 at 7:43 PM, F. Oliver Gathmann gathm...@cenix-bioscience.com wrote: On 11/12/09 11:03 AM, Tim Hoffman wrote: Hi I suppose it doesn't really matter how you go, and quite possibly the deciding factor on why you might need the wheel container and car container classes will depend on how you access data, For instance if you use something like zodb you can put arbitrary entities inside other entities, (i.e someones/garage/beetle/frontleft) where as if you data is coming from a relational dbms the wheel container class may in fact represent the table of all possible wheels. and you are using the beetle car to determine which instances of wheels (wheels in the wheel table) that it owns. That's precisely where we are coming from (we have a big legacy DB to deal with). If you have a really rigid relation model with a finite set of levels then you may find you are creating arbitrary intermediate containers just so you can define how you access the data. in this case maybe routes may be a better alternative Where as arbirtratry depth trees where each node can contain arbitrary types (think of a filesystem containing many different file types or potentially any depth) really suit traversal as anything can probably be a container. Oh - and I had hoped to be able to ditch routes now that I have model graph traversal ;-). I'd say our relational model is neither rigid nor arbitrary - we are constantly making changes but of course we stay within the limits of our domain model. Just my 2c worth. I have to think some more about this, it seems - you 2c are much appreciated, thanks! Oliver On Thu, Nov 12, 2009 at 5:40 PM, F. Oliver Gathmann gathm...@cenix-bioscience.com wrote: Hello! Coming from Pylons, I'm a newbie to the object graph traversal world, so this question might be slightly misplaced (but hopefully a no-brainer for the bfg gurus...). I very much like the concept of looking up my model object before dispatching to a view that operates on it. However, what bothers me about the standard traversal algorithm is that, for a URL like /cars/beetle/wheels/front_left I have to promote the containers (cars and wheels) to first class citizens in my model (by defining CarContainer and WheelContainer classes that I can then instantiate and return as the context object from the parent's __getitem__), where in fact they are just collections held by their mutual parent model objects (the Root object in case of the cars collection - which is in itself artificial, but I'm willing to pay that price for traversability - and the Car object in case of the wheels collection). I guess I'm asking if there is a standard, bfg-approved way of avoiding artificial container model classes - or did I just not get it yet?! I'm very grateful for any hints and pointers you may have on this issue. Thanks, Oliver -- F. Oliver Gathmann, Ph.D. Director IT Unit Cenix
Re: [Repoze-dev] object graph traversal question
On 11/12/09 1:33 PM, Chris McDonough wrote: F. Oliver Gathmann wrote: On 11/12/09 1:00 PM, Tim Hoffman wrote: Hi I have done some fairly extensive projects using traversal over a relational model and we did use intermediate container classes alot. Mainly because each major entity could have about 6 different classes of sub items that we needed to group into containers anyway I reverse engineered the entire relational model from the existing database and then autogenerated all of the intermediate classes. Quite easy to do. I was using storm as an orm over the top, which made things a lot easier Hmm... still, this feels like an artifact to me. Presumably, in most cases what you want to return when the URL asks for a collection of sub-items is the very collection you already defined in your ORM on the model object that is the current context (we are using SQLAlchemy, BTW). I cannot help but think that there should be a way to automatically return an adapted collection that supports further traversal if necessary... but I'm not sure of all the ramifications of that idea. I suspect there should be a pattern for this. This pattern might be a good one, though I don't know to what extent it can be generalized: class TraversableCollection(object): def __init__(self, parent, name, collection): self.__parent__ = parent self.__name__ = name self.collection = collection def __getitem__(self, name): return getattr(self.collection, name) # or whatever the API is class Cars(object): def __getitem__(self, name): collection = get_collection(model, name) # some helper thing return TraversableCollection(self, name, collection) Might be generalizable via a subclass: class Collection(object): def __getitem__(self, name): collection = get_collection(model, name) # some helper thing return self.collection_class(self, name, collection) class Cars(Collection): collection_class = TraversableCollection Or via Zope-style adaptation. - C Cool - this is exactly what I had in mind. I am really impressed by the number and quality of the comments I got on my little newbie question! Seems we made the right choice by basing our new server framework on repoze.bfg ;-) Cheers, Oliver ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] object graph traversal question
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 F. Oliver Gathmann wrote: On 11/12/09 1:00 PM, Tim Hoffman wrote: Hi I have done some fairly extensive projects using traversal over a relational model and we did use intermediate container classes alot. Mainly because each major entity could have about 6 different classes of sub items that we needed to group into containers anyway I reverse engineered the entire relational model from the existing database and then autogenerated all of the intermediate classes. Quite easy to do. I was using storm as an orm over the top, which made things a lot easier Hmm... still, this feels like an artifact to me. Presumably, in most cases what you want to return when the URL asks for a collection of sub-items is the very collection you already defined in your ORM on the model object that is the current context (we are using SQLAlchemy, BTW). I cannot help but think that there should be a way to automatically return an adapted collection that supports further traversal if necessary... but I'm not sure of all the ramifications of that idea. You might check out the BFG + Storm tutorial I dashed off: http://bfg.repoze.org/tutorialbin/6/ There, the container is responsible for mapping the URL segment onto the ID used to look up the contained item from the ORM. It also provides an '__iter__' API for iterating the contents (for views on the container itself) as well '__delitem__' as for removing an item, which is logically an operation on the container in traversal land (think of a directory on a filesystem). Tres. - -- === Tres Seaver +1 540-429-0999 tsea...@palladion.com Palladion Software Excellence by Designhttp://palladion.com -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkr8QzYACgkQ+gerLs4ltQ4bVQCdFtmdMPJh7Ud5fEcZcqVYeNvL ynMAnAyeEjZIzQ7pshPpxGXYcBneUBi8 =Dvif -END PGP SIGNATURE- ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev