pawel Posted July 28, 2017 Report Share Posted July 28, 2017 hi, is it possible to rename (like in sql) fetched columns in a query? session.query('select first_name as firstName, last_name as lastName from User where email is "bla@dot.com"') or some other way to rename fetched keys? I'm trying to port our current system to ftrack. It expects certain attributes on a fetched user object. I can fairly easily remap all the attributes in python but this will be double handling the hardcoded names and will lead to easy mistakes and issues. Ideally, I would like to do the renaming in the query where all the attribute names are hardcoded. Or alternatively somewhere in the ftrack web interface (without using custom attributes for everything). thank you. Link to comment Share on other sites More sharing options...
Lucas Correia Posted July 28, 2017 Report Share Posted July 28, 2017 HI Pawel, Thanks for reaching out. It currently not possible to rename attributes in the query. You would have to rely on either an intermediate data structure or potentially customize the User entity. Regards, Lucas Link to comment Share on other sites More sharing options...
pawel Posted July 31, 2017 Author Report Share Posted July 31, 2017 thank you Lucas. do you have an example of customized entity that renames attributes? I tried just adding a new attribute and setting it's value but my knowledge of the API is not extensive enough to do so. my crude implementation: logging.basicConfig(level=logging.DEBUG) class Factory(ftrack_api.entity.factory.StandardFactory): '''Entity class factory.''' def create(self, schema, bases=None): '''Create and return entity class from *schema*.''' # Optionally change bases for class to be generated. cls = super(Factory, self).create(schema, bases=bases) if str(schema['id']) == 'User': print "replacing User class" cls.default_projections = ['id', 'username', 'first_name', 'last_name'] a = ftrack_api.attribute.Attribute('firstName') cls.attributes.add(a) a.set_local_value(cls, 'foobar') return cls he above fails on `set_local_value` as it is missing session context. Probably adding an attribute is not the way it should be done. I also tried a full implementation of User sub class with custom `__getitem__` etc but that quickly become a bit problematic... renaming attributes must be a very common practice and I'm sure you have a nice solution for it. cheers. Link to comment Share on other sites More sharing options...
Eric Hermelin Posted July 31, 2017 Report Share Posted July 31, 2017 Hi Pawel, below is one possible solution, overriding the __getitem__ and __setitem__ methods, you mentioned you ran into issues overriding these methods, so sorry if there is something I have overlooked and if so please let me know what issues those were. import ftrack_api class CustomUser(ftrack_api.entity.base.Entity): custom_mapping = { 'firstName': 'first_name', 'lastName': 'last_name' } def __getitem__(self, key): if key in self.custom_mapping: key = self.custom_mapping[key] return super(CustomUser, self).__getitem__(key) def __setitem__(self, key, value): if key in self.custom_mapping: key = self.custom_mapping[key] return super(CustomUser, self).__setitem__(key, value) class Factory(ftrack_api.entity.factory.StandardFactory): '''Entity class factory.''' def create(self, schema, bases=None): '''Create and return entity class from *schema*.''' # Optionally change bases for class to be generated. if schema['id'] in ('User',): bases = [CustomUser] cls = super(Factory, self).create( schema, bases=bases ) return cls cheers Eric Link to comment Share on other sites More sharing options...
pawel Posted July 31, 2017 Author Report Share Posted July 31, 2017 thank you Eric. Let me rephrase. I didn't run into problems overriding those methods but quickly realised I will need to override many more than just those two. Like *keys* and *items* and *__contains__* and basically almost everything that gets inherited from *collection* which is the base class of everything. If I don't do that many simple things break, for instance: #user = CustomUser returned by the api if key in user: #do something will not work if I only override __getitem__ I was hoping for some solution already built into Atrribute or AttributeCollection but by browsing the code base I don't think there is any. thank you. appreciate your help. Link to comment Share on other sites More sharing options...
Eric Hermelin Posted August 2, 2017 Report Share Posted August 2, 2017 Hi Pawel, a potential workaround would be to implement a "proxy" attribute type, please keep in mind that this is more of a proof of concept and I have done very limited testing. It would have solve the keys, items and contains cases you mentioned, it might still be confusing when using projections during queries as the attributes will then have there "incorrect" names. import ftrack_api class ProxyAttribute(object): def __init__(self, name, attribute): self.name = name self.__proxy_attribute = attribute super(ProxyAttribute, self).__init__() def __getattribute__(self, attr): if attr.startswith('__') or attr in self.__dict__: try: return object.__getattribute__( self, attr ) except AttributeError: raise return object.__getattribute__( self.__proxy_attribute, attr ) class Factory(ftrack_api.entity.factory.StandardFactory): user_custom_mapping = { 'first_name': 'firstName', 'last_name': 'lastName' } def create(self, schema, bases=None): cls = super(Factory, self).create( schema, bases=bases ) if schema['id'] in ('User', ): for attribute_name, alias in self.user_custom_mapping.items(): cls.attributes.add( ProxyAttribute(alias, cls.attributes.get(attribute_name)) ) return cls cheers Eric Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.