[sqlalchemy] Subclass all dialect sqltypes
I was looking into an issue with a package and noticed that what was supposed to be an MSSQL timestamp specific case was being applied to all timestamps. Upon further investigation I found that the *mssql.TIMESTAMP* was equal to *sa.TIMESTAMP*. Both yield a *sqlalchemy.sql.sqltypese.TIMESTAMP*. Is it reasonable to expect that all dialect types yield dialect specific subclasses? If so, can this feature be added? Example: import sqlalchemy as sa from sqlalchemy.dialects import mssql type(sa.TIMESTAMP()) # sqlalchemy.sql.sqltypes.TIMESTAMP type(mssql.TIMESTAMP()) # sqlalchemy.sql.sqltypes.TIMESTAMP I would expect *mssql.TIMESTAMP() *to return a *sqlalchemy.dialects.mssql.base.TIMESTAMP* even if its not redifining the base timestamp class. This would make it consistent with other types that are redefined such as *mssql.BIT *which yields *sqlalchemy.dialects.mssql.base.BIT.* -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.
Re: [sqlalchemy] horizontal sharding and bulk_insert
On Wed, Aug 23, 2017 at 2:01 AM, Антонио Антуанwrote: > > > > So, and now we always make queries without shard_id chosing: we always make > queries on 'default' database. One exception: when we run app on master and > read statistics from geo-slaves, we point it explicitly: > "Session.query(...).set_shard_id(NODE_PREFIX)". So, yes, we use sharding > mechanizm only for that. > > My question still the same: can I override "connection_callable" member with > None on my "ShardedSessionWithDefaultBind" class? Sure, the ShardedSession is supposed to be more of an example class that you can hack on and connection_callable is a simple None/ not-None thing that is used when you flush() to get a list of connections per row, where each connection is decided based on the sharding conditionals. > > Also, if you can advise any other mechanism to make things as simple as we > have them now (with horizontal_sharding mechanism), it would be great, our > team will appreciate it :) My suggestion was that bulk_insert_mappings() / bulk_update_mappings / bulk_save_objects don't actually make the objects as any part of the session's state, nor does the existing object state of the session have any bearing on the operation of bulk_insert/bulk_update other than being part of the same transaction. So if you don't want to tinker with the state of your sharded_session, just use a different Session. If you have code like this: some_stuff = my_sharded_session.query(Stuff).filter(...).all() my_sharded_session.bulk_save_objects(objects) you could change it to this: some_stuff = my_sharded_session.query(Stuff).filter(...).all() ad_hoc_session = Session(bind=my_sharded_session.connection(shard_id='default')) ad_hoc_session.bulk_save_objects(objects) that way you don't have to change the state of my_sharded_session. It probably doesn't matter much either way, e.g. session.connection_callable=None or this, assuming there is no concurrent sharing of the sharded_session instance. > >> >> > >> > If it can help: I ALWAYS perform UPDATE/INSERT/DELETE and most of SELECT >> > queries in only one database. So, I wrote such subclass: >> > >> > >> > class ShardedSessionWithDefaultBind(ShardedSession): >> > def get_bind(self, mapper, shard_id=None, instance=None, >> > clause=None, >> > **kw): >> > if shard_id is None: >> > shard_id = default_shard_id >> > return super(ShardedSessionWithDefaultBind, >> > self).get_bind(mapper, >> > shard_id, instance, clause, **kw) >> > >> > >> > Maybe I can override "__init__" for my class and write >> > "self.connnection_callable = None"? >> > My research of sqlalchemy code didn't make me sure that it is safe >> > enough. >> > But I see, that "connection_callable" used only for checking into >> > "_bulk_insert" and "_bulk_update" functions in >> > sqlalchemy.orm.persistence >> > module. >> > So, if I 100% sure, that I ALWAYS perform INSERT/UPDATE/DELETE queries >> > in >> > only one database, can I make it? >> > >> > -- >> > SQLAlchemy - >> > The Python SQL Toolkit and Object Relational Mapper >> > >> > http://www.sqlalchemy.org/ >> > >> > To post example code, please provide an MCVE: Minimal, Complete, and >> > Verifiable Example. See http://stackoverflow.com/help/mcve for a full >> > description. >> > --- >> > You received this message because you are subscribed to the Google >> > Groups >> > "sqlalchemy" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> > an >> > email to sqlalchemy+...@googlegroups.com. >> > To post to this group, send email to sqlal...@googlegroups.com. >> > Visit this group at https://groups.google.com/group/sqlalchemy. >> > For more options, visit https://groups.google.com/d/optout. > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at https://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send
Re: [sqlalchemy] Set up a composite key using a foreign key and another column with Python
That worked! I'd still like to know about orderinglist though. Am I going to run into problems if I end up with a lot of data? -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.
Re: [sqlalchemy] Re: getting model's grandparent after persistent_to_deleted event has fired.
ok thanks. Unfortunately, I'll have to mess with my data model, but if there is no other way, I'll do it like that. On Wed, Aug 23, 2017 at 4:19 AM, Mike Bayerwrote: > On Tue, Aug 22, 2017 at 6:46 PM, cecemel wrote: > > Hello, > > > > thanks again for the answer. Perhaps my case was not clear enough. To > make > > it a bit more explicit, I updated the example accordingly. > > > > from sqlalchemy import event > > > > from sqlalchemy import * > > from sqlalchemy.ext.declarative import declarative_base > > from sqlalchemy.orm import sessionmaker, backref, relationship > > > > Base = declarative_base() > > > > > > > # > > # MODEL > > > # > > class House(Base): > > __tablename__ = 'house' > > id = Column(Integer, primary_key=True) > > rooms = relationship("Room", > > backref=backref("house", lazy="joined"), > > cascade='all, delete-orphan') > > > > > > class Room(Base): > > __tablename__ = 'room' > > id = Column(Integer, primary_key=True) > > house_id = Column(Integer, ForeignKey('house.id')) > > beds = relationship("Bed", > > backref=backref("room", lazy="joined"), > > cascade='all, delete-orphan') > > > > > > class Bed(Base): > > __tablename__ = 'bed' > > id = Column(Integer, primary_key=True) > > room_id = Column(Integer, ForeignKey('room.id')) > > > > > > > # > > # CONFIG > > > # > > def setup(): > > engine = create_engine("sqlite://", echo=True) > > > > Base.metadata.bind = engine > > Base.metadata.create_all(engine) > > > > SessionFactory = sessionmaker( > > bind=engine > > ) > > > > event.listen(SessionFactory, 'deleted_to_detached', > > listener_bed_has_been_removed) > > > > return SessionFactory > > > > > > def listener_bed_has_been_removed(session, instance): > > if type(instance) is not Bed: > > return > > > > # so, in this example, this function should be called 3 times. > > # The first time it is called, I get no problems, I can access > > instance.room.house_id the call proceeds > > # The second bed is a problem, I get the error > > # "sqlalchemy.orm.exc.DetachedInstanceError: Parent instance > 0x7f24fe14bb70> is not bound to a Session; lazy load operation of > attribute > > 'room' cannot proceed" > > > > # SO, my question is: is there ANY way to keep these references to > > parents in this function? > > > > bed_id = instance.id > > house_id = instance.room.house_id > > > > > > print("execute a service call to external service here bed_id {}, > > house_id {}".format(bed_id, house_id)) > > > > > > if __name__ == "__main__": > > session_factory = setup() > > session = session_factory() > > > > session.add(House(id=1)) > > session.add(Room(id=1, house_id=1)) > > session.add(Bed(id=1, room_id=1)) > > session.add(Bed(id=2, room_id=1)) > > session.add(Bed(id=3, room_id=1)) > > session.commit() > > > > room = session.query(Room).get(1) > > session.delete(room) > > session.commit() > > session.close() > > > > > > So, for this example, I am looking for a solution to keep the references > to > > the 'house' from the 'bed' model after flush (any solution would be > good). > > Is there perhaps a way to dynamically set a property in 'bed' -model (e.g > > house_id), once 'room'-backref has been loaded ? > > so the way you have this set up, you have not only room->bed but you > also have delete,delete-orphan cascade. this indicates your intent > that a Bed object should be deleted when it is both not associated > with any Room, as well as when its parent Room is deleted. So the > behavior you are getting is what you specified. > > if you *dont* want Bed to be deleted when Room is deleted, you'd want > to remove that delete-orphan casacde. If you then want Bed to be > directly associated with House in the absense of Room, then yes you'd > add another column house_id to Bed with a corresponding > relationship(), and you'd need to make sure that is assigned as you > want as well when the objects go into the database. > > > > > > > > > > > On Tuesday, August 22, 2017 at 5:36:39 PM UTC+2, Mike Bayer wrote: > >> > >> you would need to illustrate an MCVE of what's happening. objects > >> don't "lose track" of their related objects unless yes, you deleted > >> them, in which case you should not expect that they would be there. > >> when the object is expired, it will go to reload them, and they'll be > >> gone. > >> > >> On Tue, Aug 22, 2017 at
Re: [sqlalchemy] horizontal sharding and bulk_insert
вторник, 22 августа 2017 г., 17:29:41 UTC+3 пользователь Mike Bayer написал: > > On Tue, Aug 22, 2017 at 3:43 AM, Антонио Антуан> wrote: > > Hi guys > > I tried to implement horizontal sharding in my project. Everything is > ok, > > except bulk_inserts. > > When I run tests, I got this error: > > File "/home/anton/Projects/proj/core/model/messages.py", line 210, in > > create > > Session.bulk_insert_mappings(MessageEntity, to_commit) > > File "build/bdist.linux-x86_64/egg/sqlalchemy/orm/scoping.py", line > 157, > > in do > > return getattr(self.registry(), name)(*args, **kwargs) > > File "build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py", line > 2345, > > in bulk_insert_mappings > > mapper, mappings, False, False, return_defaults, False) > > File "build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py", line > 2416, > > in _bulk_save_mappings > > transaction.rollback(_capture_exception=True) > > File "build/bdist.linux-x86_64/egg/sqlalchemy/util/langhelpers.py", > line > > 60, in __exit__ > > compat.reraise(exc_type, exc_value, exc_tb) > > File "build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py", line > 2411, > > in _bulk_save_mappings > > mapper, mappings, transaction, isstates, return_defaults) > > File "build/bdist.linux-x86_64/egg/sqlalchemy/orm/persistence.py", > line > > 35, in _bulk_insert > > "connection_callable / per-instance sharding " > > NotImplementedError: connection_callable / per-instance sharding not > > supported in bulk_insert() > > > > I do not understand what 'connection_callable' does, but I really need > to > > implement it. Is there any ways to do it? > > The idea of bulk_insert() is strictly one of performance with some > degree of convenience; you don't need it to actually accomplish > anything as there are many other ways to achieve what it does. the > "connection_callable" thing is specifically so that an ORM persistence > operation can get at the appropriate database connection for a > particular INSERT/UPDATE/DELETE, however this adds complexity so is > not part of bulk_insert(). > > In the case of application side horizontal sharding, you'd want to > take the data you're passing to it and pre-sort it into individual > per-shard sets, then use a Session per shard to run the inserts. > > Also, application side horizontal sharding is not a great way to do > sharding in any case. If you're on Postgresql I'd strongly recommend > using table inheritance instead. > Yes, Postgresql used into a project. But I can't use inheritance, because I have several servers, each of them located in separate country. Yes, I could use inheritance and FDW, but in that case system become more complicated. When application instance runs on master node - it can read and write to master database and can only read from geo-slaves. When application instance runs on geo-slave - it can read from master, read from replicated table on current node and write data (some statistics) to some table on current node. Periodically master read data-tables (statistics) from each geo-slave and write new data on master database. Previously my project used something like that: class ClusterMeta(object): _pg_config = {} _pg_sessions = defaultdict(list) is_slave = config.get('default', 'is_slave') prefix = config.get('default', 'prefix') def _get_pg_conf(self): for name, conn_string in config['sqlalchemy'].items(): if name.startswith('conn_string_slave_'): sp = name.replace('conn_string_slave_', '').lower() self._pg_config[sp] = conn_string elif name in ['conn_string_master', 'conn_string']: sp = 'default' if name == 'conn_string' else 'master' if sp in self._pg_config: raise ValueError('{} conn_string already configured!'.format(sp.upper())) else: self._pg_config[sp] = conn_string def _create_pg_session(self, conn_string): """ :rtype: tuple(base, session) """ engine = create_engine(conn_string, convert_unicode=True) session = ScopedSession(sessionmaker(bind=engine)) base = declarative_base() base.query = session.query_property() return base, session def get_session(self, prefix, with_base=False): if prefix not in self._pg_sessions: conn_string = self._pg_config.get(prefix) if not conn_string: raise ValueError('No conn_string for prefix "%s"' % prefix) if prefix not in self._pg_sessions: self._pg_sessions[prefix] = [] s = self._create_pg_session(conn_string) self._pg_sessions[prefix].insert(0, s) else: s = self._pg_sessions[prefix][0] return s if