From d14a4b480c3b43885707e4a6e2466589971ff4d5 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 17 Aug 2015 17:04:33 -0400 Subject: - merge of ticket_3514 None-handling branch - Fixes to the ORM and to the postgresql JSON type regarding the ``None`` constant in conjunction with the Postgresql :class:`.JSON` type. When the :paramref:`.JSON.none_as_null` flag is left at its default value of ``False``, the ORM will now correctly insert the Json "'null'" string into the column whenever the value on the ORM object is set to the value ``None`` or when the value ``None`` is used with :meth:`.Session.bulk_insert_mappings`, **including** if the column has a default or server default on it. This makes use of a new type-level flag "evaluates_none" which is implemented by the JSON type based on the none_as_null flag. fixes #3514 - Added a new constant :attr:`.postgresql.JSON.NULL`, indicating that the JSON NULL value should be used for a value regardless of other settings. part of fixes #3514 --- lib/sqlalchemy/orm/mapper.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'lib/sqlalchemy/orm/mapper.py') diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 48fbaae32..3efaa45ac 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1914,6 +1914,19 @@ class Mapper(InspectionAttr): """ + @_memoized_configured_property + def _insert_cols_evaluating_none(self): + return dict( + ( + table, + frozenset( + col.key for col in columns + if col.type.evaluates_none + ) + ) + for table, columns in self._cols_by_table.items() + ) + @_memoized_configured_property def _insert_cols_as_none(self): return dict( @@ -1922,7 +1935,8 @@ class Mapper(InspectionAttr): frozenset( col.key for col in columns if not col.primary_key and - not col.server_default and not col.default) + not col.server_default and not col.default + and not col.type.evaluates_none) ) for table, columns in self._cols_by_table.items() ) -- cgit v1.2.1 From 0127ac668e405584d74c92768a9f0dc7913798fe Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 24 Aug 2015 21:52:33 -0400 Subject: - re-document and fully cross link all of configure_mappers(), mapper_configured(), after_configured(), and before_configured(). --- lib/sqlalchemy/orm/mapper.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'lib/sqlalchemy/orm/mapper.py') diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 3efaa45ac..1a46667c5 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -2696,7 +2696,33 @@ def configure_mappers(): have been constructed thus far. This function can be called any number of times, but in - most cases is handled internally. + most cases is invoked automatically, the first time mappings are used, + as well as whenever mappings are used and additional not-yet-configured + mappers have been constructed. + + Points at which this occur include when a mapped class is instantiated + into an instance, as well as when the :meth:`.Session.query` method + is used. + + The :func:`.configure_mappers` function provides several event hooks + that can be used to augment its functionality. These methods include: + + * :meth:`.MapperEvents.before_configured` - called once before + :func:`.configure_mappers` does any work; this can be used to establish + additional options, properties, or related mappings before the operation + proceeds. + + * :meth:`.MapperEvents.mapper_configured` - called as each indivudal + :class:`.Mapper` is configured within the process; will include all + mapper state except for backrefs set up by other mappers that are still + to be configured. + + * :meth:`.MapperEvents.after_configured` - called once after + :func:`.configure_mappers` is complete; at this stage, all + :class:`.Mapper` objects that are known to SQLAlchemy will be fully + configured. Note that the calling application may still have other + mappings that haven't been produced yet, such as if they are in modules + as yet unimported. """ -- cgit v1.2.1 From 03797b78475bec9fb9c15f8e926414f3720a273c Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 10 Sep 2015 10:00:46 -0400 Subject: - add a new FAQ recipe for "walk all objects", replacing the need to use mapper.cascade_iterator() for this purpose as it was not really designed for that use case. Add docs to cascade_iterator() pointing to the recipe. fixes #3498 --- lib/sqlalchemy/orm/mapper.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'lib/sqlalchemy/orm/mapper.py') diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 1a46667c5..21577f5ea 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -2571,15 +2571,24 @@ class Mapper(InspectionAttr): for all relationships that meet the given cascade rule. :param type_: - The name of the cascade rule (i.e. save-update, delete, - etc.) + The name of the cascade rule (i.e. ``"save-update"``, ``"delete"``, + etc.). + + .. note:: the ``"all"`` cascade is not accepted here. For a generic + object traversal function, see :ref:`faq_walk_objects`. :param state: The lead InstanceState. child items will be processed per the relationships defined for this object's mapper. - the return value are object instances; this provides a strong - reference so that they don't fall out of scope immediately. + :return: the method yields individual object instances. + + .. seealso:: + + :ref:`unitofwork_cascades` + + :ref:`faq_walk_objects` - illustrates a generic function to + traverse all objects without relying on cascades. """ visited_states = set() -- cgit v1.2.1 From 80aeba3d5e0269eb689d991ca0b8e281715113ed Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 19 Sep 2015 13:12:08 -0400 Subject: - Added a new type-level modifier :meth:`.TypeEngine.evaluates_none` which indicates to the ORM that a positive set of None should be persisted as the value NULL, instead of omitting the column from the INSERT statement. This feature is used both as part of the implementation for :ticket:`3514` as well as a standalone feature available on any type. fixes #3250 - add new documentation section illustrating the "how to force null" use case of #3250 - alter our change from #3514 so that the class-level flag is now called "should_evaluate_none"; so that "evaluates_none" is now a generative method. --- lib/sqlalchemy/orm/mapper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/sqlalchemy/orm/mapper.py') diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 21577f5ea..5ade4b966 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1921,7 +1921,7 @@ class Mapper(InspectionAttr): table, frozenset( col.key for col in columns - if col.type.evaluates_none + if col.type.should_evaluate_none ) ) for table, columns in self._cols_by_table.items() @@ -1936,7 +1936,7 @@ class Mapper(InspectionAttr): col.key for col in columns if not col.primary_key and not col.server_default and not col.default - and not col.type.evaluates_none) + and not col.type.should_evaluate_none) ) for table, columns in self._cols_by_table.items() ) -- cgit v1.2.1 From 0e4c4d7efc08d04c3c0ae960428b08ada37e4a91 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 14 Dec 2015 17:24:47 -0500 Subject: - Fixed bug in :meth:`.Update.return_defaults` which would cause all insert-default holding columns not otherwise included in the SET clause (such as primary key cols) to get rendered into the RETURNING even though this is an UPDATE. - Major fixes to the :paramref:`.Mapper.eager_defaults` flag, this flag would not be honored correctly in the case that multiple UPDATE statements were to be emitted, either as part of a flush or a bulk update operation. Additionally, RETURNING would be emitted unnecessarily within update statements. fixes #3609 --- lib/sqlalchemy/orm/mapper.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/sqlalchemy/orm/mapper.py') diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 5ade4b966..95aa14a26 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1970,12 +1970,24 @@ class Mapper(InspectionAttr): ( table, frozenset([ - col for col in columns + col.key for col in columns if col.server_default is not None]) ) for table, columns in self._cols_by_table.items() ) + @_memoized_configured_property + def _server_onupdate_default_cols(self): + return dict( + ( + table, + frozenset([ + col.key for col in columns + if col.server_onupdate is not None]) + ) + for table, columns in self._cols_by_table.items() + ) + @property def selectable(self): """The :func:`.select` construct this :class:`.Mapper` selects from -- cgit v1.2.1