📄 schema.py
字号:
listener('after-create', self, bind) def drop_all(self, bind=None, tables=None, checkfirst=True): """Drop all tables stored in this metadata. This will conditionally drop tables depending on if they currently exist in the database. bind A ``Connectable`` used to access the database; if None, uses the existing bind on this ``MetaData``, if any. tables Optional list of ``Table`` objects, which is a subset of the total tables in the ``MetaData`` (others are ignored). """ if bind is None: bind = _bind_or_error(self) for listener in self.ddl_listeners['before-drop']: listener('before-drop', self, bind) bind.drop(self, checkfirst=checkfirst, tables=tables) for listener in self.ddl_listeners['after-drop']: listener('after-drop', self, bind)class ThreadLocalMetaData(MetaData): """A MetaData variant that presents a different ``bind`` in every thread. Makes the ``bind`` property of the MetaData a thread-local value, allowing this collection of tables to be bound to different ``Engine`` implementations or connections in each thread. The ThreadLocalMetaData starts off bound to None in each thread. Binds must be made explicitly by assigning to the ``bind`` property or using ``connect()``. You can also re-bind dynamically multiple times per thread, just like a regular ``MetaData``. Use this type of MetaData when your tables are present in more than one database and you need to address them simultanesouly. """ __visit_name__ = 'metadata' def __init__(self): """Construct a ThreadLocalMetaData.""" self.context = util.ThreadLocal() self.__engines = {} super(ThreadLocalMetaData, self).__init__() # @deprecated def connect(self, bind, **kwargs): """Bind to an Engine in the caller's thread. Use ``metadata.bind=<engine>`` or ``metadata.bind=<url>``. bind A string, ``URL``, ``Engine`` or ``Connection`` instance. If a string or ``URL``, will be passed to ``create_engine()`` along with ``\**kwargs`` to produce the engine which to connect to. Otherwise connects directly to the given ``Engine``. """ global URL if URL is None: from sqlalchemy.engine.url import URL if isinstance(bind, (basestring, URL)): try: engine = self.__engines[bind] except KeyError: engine = sqlalchemy.create_engine(bind, **kwargs) bind = engine self._bind_to(bind) connect = util.deprecated(connect) def bind(self): """The bound Engine or Connection for this thread. This property may be assigned an Engine or Connection, or assigned a string or URL to automatically create a basic Engine for this bind with ``create_engine()``.""" return getattr(self.context, '_engine', None) def _bind_to(self, bind): """Bind to a Connectable in the caller's thread.""" global URL if URL is None: from sqlalchemy.engine.url import URL if isinstance(bind, (basestring, URL)): try: self.context._engine = self.__engines[bind] except KeyError: e = sqlalchemy.create_engine(bind) self.__engines[bind] = e self.context._engine = e else: # TODO: this is squirrely. we shouldnt have to hold onto engines # in a case like this if bind not in self.__engines: self.__engines[bind] = bind self.context._engine = bind bind = property(bind, _bind_to) def is_bound(self): """True if there is a bind for this thread.""" return (hasattr(self.context, '_engine') and self.context._engine is not None) def dispose(self): """Dispose any and all ``Engines`` to which this ``ThreadLocalMetaData`` has been connected.""" for e in self.__engines.values(): if hasattr(e, 'dispose'): e.dispose()class SchemaVisitor(visitors.ClauseVisitor): """Define the visiting for ``SchemaItem`` objects.""" __traverse_options__ = {'schema_visitor':True}class DDL(object): """A literal DDL statement. Specifies literal SQL DDL to be executed by the database. DDL objects can be attached to ``Tables`` or ``MetaData`` instances, conditionally executing SQL as part of the DDL lifecycle of those schema items. Basic templating support allows a single DDL instance to handle repetitive tasks for multiple tables. Examples:: tbl = Table('users', metadata, Column('uid', Integer)) # ... DDL('DROP TRIGGER users_trigger').execute_at('before-create', tbl) spow = DDL('ALTER TABLE %(table)s SET secretpowers TRUE', on='somedb') spow.execute_at('after-create', tbl) drop_spow = DDL('ALTER TABLE users SET secretpowers FALSE') connection.execute(drop_spow) """ def __init__(self, statement, on=None, context=None): """Create a DDL statement. statement A string or unicode string to be executed. Statements will be processed with Python's string formatting operator. See the ``context`` argument and the ``execute_at`` method. A literal '%' in a statement must be escaped as '%%'. Bind parameters are not available in DDL statements. on Optional filtering criteria. May be a string or a callable predicate. If a string, it will be compared to the name of the executing database dialect:: DDL('something', on='postgres') If a callable, it will be invoked with three positional arguments: event The name of the event that has triggered this DDL, such as 'after-create' Will be None if the DDL is executed explicitly. schema_item A SchemaItem instance, such as ``Table`` or ``MetaData``. May be None if the DDL is executed explicitly. connection The ``Connection`` being used for DDL execution If the callable returns a true value, the DDL statement will be executed. context Optional dictionary, defaults to None. These values will be available for use in string substitutions on the DDL statement. """ if not isinstance(statement, basestring): raise exceptions.ArgumentError( "Expected a string or unicode SQL statement, got '%r'" % statement) if (on is not None and (not isinstance(on, basestring) and not callable(on))): raise exceptions.ArgumentError( "Expected the name of a database dialect or a callable for " "'on' criteria, got type '%s'." % type(on).__name__) self.statement = statement self.on = on self.context = context or {} def execute(self, bind, schema_item=None): """Execute this DDL immediately. Executes the DDL statement in isolation using the supplied ``Connectable``. If the DDL has a conditional ``on`` criteria, it will be invoked with None as the event. bind An Engine or Connection schema_item Optional, defaults to None. Will be passed to the ``on`` callable criteria, if any, and may provide string expansion data for the statement. See ``execute_at`` for more information. """ # no bind params are supported if self._should_execute(None, schema_item, bind): executable = expression.text(self._expand(schema_item, bind)) return bind.execute(executable) else: bind.engine.logger.info("DDL execution skipped, criteria not met.") def execute_at(self, event, schema_item): """Link execution of this DDL to the DDL lifecycle of a SchemaItem. Links this ``DDL`` to a ``Table`` or ``MetaData`` instance, executing it when that schema item is created or dropped. event One of the events defined in the schema item's ``.ddl_events``; e.g. 'before-create', 'after-create', 'before-drop' or 'after-drop' schema_item A Table or MetaData instance When operating on Table events, the following additional ``statement`` string substitions are available:: %(table)s - the Table name, with any required quoting applied %(schema)s - the schema name, with any required quoting applied %(fullname)s - the Table name including schema, quoted if needed The DDL's ``context``, if any, will be combined with the standard substutions noted above. Keys present in the context will override the standard substitutions. A DDL instance can be linked to any number of schema items. The statement subsitution support allows for DDL instances to be used in a template fashion. ``execute_at`` builds on the ``append_ddl_listener`` interface of MetaDta and Table objects. Caveat: Creating or dropping a Table in isolation will also trigger any DDL set to ``execute_at`` that Table's MetaData. This may change in a future release. """ if not hasattr(schema_item, 'ddl_listeners'): raise exceptions.ArgumentError( "%s does not support DDL events" % type(schema_item).__name__) if event not in schema_item.ddl_events: raise exceptions.ArgumentError( "Unknown event, expected one of (%s), got '%r'" % (', '.join(schema_item.ddl_events), event)) schema_item.ddl_listeners[event].append(self) return self def __call__(self, event, schema_item, bind): """Execute the DDL as a ddl_listener.""" if self._should_execute(event, schema_item, bind): statement = expression.text(self._expand(schema_item, bind)) return bind.execute(statement) def _expand(self, schema_item, bind): return self.statement % self._prepare_context(schema_item, bind) def _should_execute(self, event, schema_item, bind): if self.on is None: return True elif isinstance(self.on, basestring): return self.on == bind.engine.name else: return self.on(event, schema_item, bind) def _prepare_context(self, schema_item, bind): # table events can substitute table and schema name if isinstance(schema_item, Table): context = self.context.copy() preparer = bind.dialect.identifier_preparer path = preparer.format_table_seq(schema_item) if len(path) == 1: table, schema = path[0], '' else: table, schema = path[-1], path[0] context.setdefault('table', table) context.setdefault('schema', schema) context.setdefault('fullname', preparer.format_table(schema_item)) return context else: return self.context def __repr__(self): return '<%s@%s; %s>' % ( type(self).__name__, id(self), ', '.join([repr(self.statement)] + ['%s=%r' % (key, getattr(self, key)) for key in ('on', 'context') if getattr(self, key)]))def _bind_or_error(schemaitem): bind = schemaitem.bind if not bind: name = schemaitem.__class__.__name__ label = getattr(schemaitem, 'fullname', getattr(schemaitem, 'name', None)) if label: item = '%s %r' % (name, label) else: item = name if isinstance(schemaitem, MetaData): bindable = "the %s's .bind" % name else: bindable = "this %s's .metadata.bind" % name msg = ('The %s is not bound to an Engine or Connection. ' 'Execution can not proceed without a database to execute ' 'against. Either execute with an explicit connection or ' 'assign %s to enable implicit execution.') % (item, bindable) raise exceptions.UnboundExecutionError(msg) return bind
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -