[sqlalchemy] Re: Questions about polymorphic mappers
Michael Bayer wrote: Simon King wrote: [requirements for instances returned from MapperExtension.create_instance] at this point the entity_name should get set after your custom create_instance is called (at least thats in the trunk). init_attr is not required, it pre-sets attributes on the object that are otherwise auto-created later (but the autocreation step throws a single AttributeError per attribute, which hits performance a little bit). Thanks a lot for explaining that. It looks to me like I would be better off simply using this method to load my class hierarchy, rather than trying to twist polymorphic_identity into something that it was never meant to do. Also, adding get_polymorphic_identity as a MapperExtension method would add an overhead for every single object load for what is probably a very infrequently used feature - I'd hate to be responsible for that! Yet again, SQLAlchemy is already able to do exactly what I want - sorry it's taken a while for me to realise it. Cheers, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Questions about polymorphic mappers
Micheal Bayer wrote: id rather just add another plugin point on MapperExtension for this, which takes place before the polymorphic decision stage at the top of the _instance method, like get_polymorphic_identity(). that way you could do all of this stuff cleanly in an extension (and id do that instead of making polymorphic_identity into a list). hows that sound? That would be ideal for me, and would seem to be the most flexible solution as well - it leaves the decision for which class to use up to the application. What would it actually return, though? An instance ready to be populated? Thanks a lot, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Questions about polymorphic mappers
at this point the entity_name should get set after your custom create_instance is called (at least thats in the trunk). init_attr is not required, it pre-sets attributes on the object that are otherwise auto-created later (but the autocreation step throws a single AttributeError per attribute, which hits performance a little bit). On Jan 15, 2007, at 12:19 PM, King Simon-NFHD78 wrote: Michael Bayer wrote: you can still override create_instance() as well and try to spit out subclasses that are otherwise not mapped. This was something I looked at a while ago as well, and I wasn't sure what the requirements on objects returned from create_instance were. If it is not overridden, the mapper calls _create_instance, which sets _entity_name and calls attribute_manager.init_attr. How important are these things to the rest of the library? Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Questions about polymorphic mappers
Michael Bayer wrote: i think using the polymorphic_map is OK. i downplayed its existence since I felt it was confusing to people, which is also the reason i made the _polymorphic_map argument to mapper private; it was originally public. but it seemed like it was producing two ways of doing the same thing so i made it private. OK - I'll carry on using that then. using class_mapper() function instead of class.mapper Ah - that's what I was missing. I hadn't seen the class_mapper function. Thanks for that. as far as having multiple polymorphic_identity values map to the same class, i would think we could just have polymorphic_identity be a list instead of a scalar. right now, if you just inserted multiple values for the same class in polymorphic_map, it would *almost* work except that the save() process is hardwiring the polymorphic_on column to the single polymorphic_identity value no matter what its set to. so attached is an untested patch which accepts either a scalar or a list value for polymorphic_identity, and if its a list then instances need their polymorphic_on attribute set to a valid entry before flushing. try this out and see if it does what you need, and i can easily enough add this to the trunk to be available in the next release (though id need to write some tests also). I think this would definitely be a useful feature, and in fact I was originally going to attempt (or at least suggest!) something like that myself. I'll try the patch and let you know how well it works. However, I still have a situation where I would like to be able to use a default class for unknown types. I don't want to hard-code all the possible options up-front - only the ones that I actually want to treat specially. I've been playing around with some different options, and this is what I've ended up with: class EmployeeMeta(type): def __call__(cls, kind, _fix_class=True, **kwargs): if not _fix_class: return type.__call__(cls, kind=kind, **kwargs) cls = get_employee_class(kind) return cls(kind=kind, _fix_class=False, **kwargs) def get_employee_class(kind): if kind == 'manager': return Manager else: return Employee class Employee(object): __metaclass__ = EmployeeMeta class Manager(Employee): pass class EmployeeMapperExtension(sa.MapperExtension): def create_instance(self, mapper, selectcontext, row, class_): cls = get_employee_class(row[employee_table.c.kind]) if class_ != cls: return sa.class_mapper(cls)._instance(selectcontext, row) return sa.EXT_PASS assign_mapper(ctx, Employee, employee_table, extension=EmployeeMapperExtension()) assign_mapper(ctx, Manager, inherits=Employee.mapper) This seems to do the right thing - Manager instances get created for managers, but any other row becomes an Employee. To add a subclass for another row type, I just need to adapt the get_employee_class function and add another call to assign_mapper. With a bit more work in the metaclass, it could all be done with a special attribute in the subclass. The only thing I'm not sure about is the mapper extension - is it OK to call the mapper._instance method, or is there a better way to do this? Thanks again, Simon --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~--- inheritance_test.py Description: inheritance_test.py
[sqlalchemy] Re: Questions about polymorphic mappers
King Simon-NFHD78 wrote: class EmployeeMapperExtension(sa.MapperExtension): def create_instance(self, mapper, selectcontext, row, class_): cls = get_employee_class(row[employee_table.c.kind]) if class_ != cls: return sa.class_mapper(cls)._instance(selectcontext, row) return sa.EXT_PASS The only thing I'm not sure about is the mapper extension - is it OK to call the mapper._instance method, or is there a better way to do this? if you call _instance like that, youre already well inside the _instance method of the calling mapper...so its not a great way to do it since a lot of redundant stuff will happen which may have negative side effects. id rather just add another plugin point on MapperExtension for this, which takes place before the polymorphic decision stage at the top of the _instance method, like get_polymorphic_identity(). that way you could do all of this stuff cleanly in an extension (and id do that instead of making polymorphic_identity into a list). hows that sound? --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---