You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by av...@apache.org on 2017/03/28 12:08:42 UTC

[1/3] incubator-ariatosca git commit: ARIA-132-Models-cascading-deletion-raises-constraint-errors [Forced Update!]

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-133-Add-status-related-methods-to-Execution-Task-and-Node-models a08f6d657 -> 02fedd928 (forced update)


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 8b619bf..8355521 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -41,7 +41,7 @@ from . import (
 )
 
 
-class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public-methods
+class ServiceTemplateBase(TemplateModelMixin):
     """
     A service template is a source for creating :class:`Service` instances.
 
@@ -90,7 +90,6 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     :vartype created_at: :class:`datetime.datetime`
     :ivar updated_at: Update timestamp
     :vartype updated_at: :class:`datetime.datetime`
-
     :ivar services: Instantiated services
     :vartype services: [:class:`Service`]
     """
@@ -108,121 +107,151 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
     description = Column(Text)
     main_file_name = Column(Text)
+    created_at = Column(DateTime, nullable=False, index=True)
+    updated_at = Column(DateTime)
+
+    # region foreign keys
 
     @declared_attr
-    def meta_data(cls):
-        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
-        return relationship.many_to_many(cls, 'metadata', dict_key='name')
+    def substitution_template_fk(cls):
+        """For ServiceTemplate one-to-one to SubstitutionTemplate"""
+        return relationship.foreign_key('substitution_template', nullable=True)
 
     @declared_attr
-    def node_templates(cls):
-        return relationship.one_to_many(cls, 'node_template', dict_key='name')
+    def node_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def group_templates(cls):
-        return relationship.one_to_many(cls, 'group_template', dict_key='name')
+    def group_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def policy_templates(cls):
-        return relationship.one_to_many(cls, 'policy_template', dict_key='name')
+    def policy_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def substitution_template(cls):
-        return relationship.one_to_one(cls, 'substitution_template')
+    def relationship_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+    def capability_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def outputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
+    def interface_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def workflow_templates(cls):
-        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
+    def artifact_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
 
     @declared_attr
-    def plugin_specifications(cls):
-        return relationship.one_to_many(cls, 'plugin_specification', dict_key='name')
+    def substitution_template(cls):
+        return relationship.one_to_one(
+            cls, 'substitution_template', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def node_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='node_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='node_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def group_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='group_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='group_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def policy_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='policy_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='policy_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def relationship_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='relationship_type_fk',
-                                       other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='relationship_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def capability_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='capability_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='capability_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def interface_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='interface_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='interface_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def artifact_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='artifact_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='artifact_type_fk', back_populates=relationship.NO_BACK_POP)
 
-    # region orchestration
+    # endregion
 
-    created_at = Column(DateTime, nullable=False, index=True)
-    updated_at = Column(DateTime)
+    # region one_to_many relationships
 
-    # endregion
+    @declared_attr
+    def services(cls):
+        return relationship.one_to_many(cls, 'service')
 
-    # region foreign keys
+    @declared_attr
+    def operation_templates(cls):
+        return relationship.one_to_many(cls, 'operation_template')
 
     @declared_attr
-    def substitution_template_fk(cls):
-        """For ServiceTemplate one-to-one to SubstitutionTemplate"""
-        return relationship.foreign_key('substitution_template', nullable=True)
+    def node_templates(cls):
+        return relationship.one_to_many(cls, 'node_template', dict_key='name')
 
     @declared_attr
-    def node_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def group_templates(cls):
+        return relationship.one_to_many(cls, 'group_template', dict_key='name')
 
     @declared_attr
-    def group_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def policy_templates(cls):
+        return relationship.one_to_many(cls, 'policy_template', dict_key='name')
 
     @declared_attr
-    def policy_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def workflow_templates(cls):
+        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
 
     @declared_attr
-    def relationship_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def plugin_specifications(cls):
+        return relationship.one_to_many(cls, 'plugin_specification', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
-    def capability_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def meta_data(cls):
+        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
+        return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
-    def interface_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
-    def artifact_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def outputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     # endregion
 
@@ -394,7 +423,6 @@ class NodeTemplateBase(TemplateModelMixin):
     :vartype requirement_templates: [:class:`RequirementTemplate`]
     :ivar target_node_template_constraints: Constraints for filtering relationship targets
     :vartype target_node_template_constraints: [:class:`FunctionType`]
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar group_templates: We are a member of these groups
@@ -413,14 +441,54 @@ class NodeTemplateBase(TemplateModelMixin):
                           'service_template_fk',
                           'service_template_name']
 
+    # region foreign_keys
+
+    @declared_attr
+    def type_fk(cls):
+        """For NodeTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
+
+    @declared_attr
+    def service_template_fk(cls):
+        """For ServiceTemplate one-to-many to NodeTemplate"""
+        return relationship.foreign_key('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_template_name(cls):
+        """Required for use by SQLAlchemy queries"""
+        return association_proxy('service_template', 'name')
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def nodes(cls):
+        return relationship.one_to_many(cls, 'node')
+
+    # endregion
+
+    # region many_to_one relationships
+
     @declared_attr
     def type(cls):
-        return relationship.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
-    description = Column(Text)
-    default_instances = Column(Integer, default=1)
-    min_instances = Column(Integer, default=0)
-    max_instances = Column(Integer, default=None)
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
     def properties(cls):
@@ -440,33 +508,15 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def requirement_templates(cls):
-        return relationship.one_to_many(cls, 'requirement_template', child_fk='node_template_fk',
-                                        child_property='node_template')
-
-    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
-
-    # region foreign_keys
-
-    @declared_attr
-    def type_fk(cls):
-        """For NodeTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
-
-    @declared_attr
-    def service_template_fk(cls):
-        """For ServiceTemplate one-to-many to NodeTemplate"""
-        return relationship.foreign_key('service_template')
+        return relationship.one_to_many(cls, 'requirement_template', child_fk='node_template_fk')
 
     # endregion
 
-    # region association proxies
-
-    @declared_attr
-    def service_template_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service_template', 'name')
-
-    # endregion
+    description = Column(Text)
+    default_instances = Column(Integer, default=1)
+    min_instances = Column(Integer, default=0)
+    max_instances = Column(Integer, default=None)
+    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     def is_target_node_valid(self, target_node_template):
         if self.target_node_template_constraints:
@@ -557,7 +607,6 @@ class GroupTemplateBase(TemplateModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar policy_templates: Policy templates enacted on this group
@@ -571,38 +620,66 @@ class GroupTemplateBase(TemplateModelMixin):
     __private_fields__ = ['type_fk',
                           'service_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    # region foreign keys
 
-    description = Column(Text)
+    @declared_attr
+    def type_fk(cls):
+        """For GroupTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def node_templates(cls):
-        return relationship.many_to_many(cls, 'node_template')
+    def service_template_fk(cls):
+        """For ServiceTemplate one-to-many to GroupTemplate"""
+        return relationship.foreign_key('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def groups(cls):
+        return relationship.one_to_many(cls, 'group')
 
     @declared_attr
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
-    # region foreign keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For GroupTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
 
     @declared_attr
-    def service_template_fk(cls):
-        """For ServiceTemplate one-to-many to GroupTemplate"""
-        return relationship.foreign_key('service_template')
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
     # endregion
 
+    # region many_to_many relationships
+
+    @declared_attr
+    def node_templates(cls):
+        return relationship.many_to_many(cls, 'node_template')
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -622,7 +699,7 @@ class GroupTemplateBase(TemplateModelMixin):
         utils.instantiate_dict(self, group.interfaces, self.interface_templates)
         if self.node_templates:
             for node_template in self.node_templates:
-                group.nodes += node_template.nodes.all()
+                group.nodes += node_template.nodes
         return group
 
     def validate(self):
@@ -664,7 +741,6 @@ class PolicyTemplateBase(TemplateModelMixin):
     :vartype group_templates: [:class:`GroupTemplate`]
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar policies: Instantiated policies
@@ -673,14 +749,51 @@ class PolicyTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'policy_template'
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
+    __private_fields__ = ['type_fk', 'service_template_fk']
+
+    # region foreign keys
+
+    @declared_attr
+    def type_fk(cls):
+        """For PolicyTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
+
+    @declared_attr
+    def service_template_fk(cls):
+        """For ServiceTemplate one-to-many to PolicyTemplate"""
+        return relationship.foreign_key('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def policies(cls):
+        return relationship.one_to_many(cls, 'policy')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
 
     @declared_attr
     def type(cls):
-        return relationship.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
-    description = Column(Text)
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
     def node_templates(cls):
@@ -694,20 +807,10 @@ class PolicyTemplateBase(TemplateModelMixin):
     def properties(cls):
         return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
-    # region foreign keys
-
-    @declared_attr
-    def type_fk(cls):
-        """For PolicyTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
-
-    @declared_attr
-    def service_template_fk(cls):
-        """For ServiceTemplate one-to-many to PolicyTemplate"""
-        return relationship.foreign_key('service_template')
-
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -725,10 +828,10 @@ class PolicyTemplateBase(TemplateModelMixin):
         utils.instantiate_dict(self, policy.properties, self.properties)
         if self.node_templates:
             for node_template in self.node_templates:
-                policy.nodes += node_template.nodes.all()
+                policy.nodes += node_template.nodes
         if self.group_templates:
             for group_template in self.group_templates:
-                policy.groups += group_template.groups.all()
+                policy.groups += group_template.groups
         return policy
 
     def validate(self):
@@ -761,7 +864,6 @@ class SubstitutionTemplateBase(TemplateModelMixin):
     :vartype node_type: :class:`Type`
     :ivar mappings: Requirement and capability mappings
     :vartype mappings: {basestring: :class:`SubstitutionTemplateMapping`}
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar substitutions: Instantiated substitutions
@@ -772,20 +874,44 @@ class SubstitutionTemplateBase(TemplateModelMixin):
 
     __private_fields__ = ['node_type_fk']
 
+    # region foreign keys
+
     @declared_attr
-    def node_type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def node_type_fk(cls):
+        """For SubstitutionTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def substitutions(cls):
+        return relationship.one_to_many(cls, 'substitution')
 
     @declared_attr
     def mappings(cls):
         return relationship.one_to_many(cls, 'substitution_template_mapping', dict_key='name')
 
-    # region foreign keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def node_type_fk(cls):
-        """For SubstitutionTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def node_type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
 
     # endregion
 
@@ -830,7 +956,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
     :vartype capability_template: :class:`CapabilityTemplate`
     :ivar requirement_template: Requirement template in the node template
     :vartype requirement_template: :class:`RequirementTemplate`
-
     :ivar substitution_template: Containing substitution template
     :vartype substitution_template: :class:`SubstitutionTemplate`
     """
@@ -842,18 +967,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
                           'capability_template_fk',
                           'requirement_template_fk']
 
-    @declared_attr
-    def node_template(cls):
-        return relationship.one_to_one(cls, 'node_template')
-
-    @declared_attr
-    def capability_template(cls):
-        return relationship.one_to_one(cls, 'capability_template')
-
-    @declared_attr
-    def requirement_template(cls):
-        return relationship.one_to_one(cls, 'requirement_template')
-
     # region foreign keys
 
     @declared_attr
@@ -878,6 +991,45 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.one_to_one(
+            cls, 'node_template', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def capability_template(cls):
+        return relationship.one_to_one(
+            cls, 'capability_template', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def requirement_template(cls):
+        return relationship.one_to_one(
+            cls, 'requirement_template', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def substitution_template(cls):
+        return relationship.many_to_one(cls, 'substitution_template', back_populates='mappings')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -889,7 +1041,7 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
     def instantiate(self, container):
         from . import models
         context = ConsumptionContext.get_thread_local()
-        nodes = self.node_template.nodes.all()
+        nodes = self.node_template.nodes
         if len(nodes) == 0:
             context.validation.report(
                 'mapping "{0}" refers to node template "{1}" but there are no '
@@ -950,7 +1102,6 @@ class RequirementTemplateBase(TemplateModelMixin):
     :vartype target_node_template_constraints: [:class:`FunctionType`]
     :ivar relationship_template: Template for relationships (optional)
     :vartype relationship_template: :class:`RelationshipTemplate`
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar substitution_template_mapping: Our contribution to service substitution
@@ -967,28 +1118,6 @@ class RequirementTemplateBase(TemplateModelMixin):
                           'node_template_fk',
                           'relationship_template_fk']
 
-    @declared_attr
-    def target_node_type(cls):
-        return relationship.many_to_one(cls, 'type', fk='target_node_type_fk',
-                                        parent_property=False)
-
-    @declared_attr
-    def target_node_template(cls):
-        return relationship.one_to_one(cls, 'node_template', fk='target_node_template_fk',
-                                       other_property=False)
-
-    @declared_attr
-    def target_capability_type(cls):
-        return relationship.one_to_one(cls, 'type', fk='target_capability_type_fk',
-                                       other_property=False)
-
-    target_capability_name = Column(Text)
-    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
-
-    @declared_attr
-    def relationship_template(cls):
-        return relationship.one_to_one(cls, 'relationship_template')
-
     # region foreign keys
 
     @declared_attr
@@ -1007,17 +1136,73 @@ class RequirementTemplateBase(TemplateModelMixin):
         return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def node_template_fk(cls):
-        """For NodeTemplate one-to-many to RequirementTemplate"""
-        return relationship.foreign_key('node_template')
+    def node_template_fk(cls):
+        """For NodeTemplate one-to-many to RequirementTemplate"""
+        return relationship.foreign_key('node_template')
+
+    @declared_attr
+    def relationship_template_fk(cls):
+        """For RequirementTemplate one-to-one to RelationshipTemplate"""
+        return relationship.foreign_key('relationship_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def target_node_template(cls):
+        return relationship.one_to_one(cls,
+                                       'node_template',
+                                       fk='target_node_template_fk',
+                                       back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def target_capability_type(cls):
+        return relationship.one_to_one(cls,
+                                       'type',
+                                       fk='target_capability_type_fk',
+                                       back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.one_to_one(cls,
+                                       'relationship_template',
+                                       back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def relationships(cls):
+        return relationship.one_to_many(cls, 'relationship')
+
+    @declared_attr
+    def target_node_type(cls):
+        return relationship.many_to_one(
+            cls, 'type', fk='target_node_type_fk', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def relationship_template_fk(cls):
-        """For RequirementTemplate one-to-one to RelationshipTemplate"""
-        return relationship.foreign_key('relationship_template', nullable=True)
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template', fk='node_template_fk')
+
+    # endregion
+
+    # region many_to_many relationships
 
     # endregion
 
+    target_capability_name = Column(Text)
+    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
+
     def find_target(self, source_node_template):
         context = ConsumptionContext.get_thread_local()
 
@@ -1137,7 +1322,6 @@ class RelationshipTemplateBase(TemplateModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
-
     :ivar requirement_template: Containing requirement template
     :vartype requirement_template: :class:`RequirementTemplate`
     :ivar relationships: Instantiated relationships
@@ -1148,29 +1332,53 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     __private_fields__ = ['type_fk']
 
+    # region foreign keys
+
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def type_fk(cls):
+        """For RelationshipTemplate many-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
-    description = Column(Text)
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def relationships(cls):
+        return relationship.one_to_many(cls, 'relationship')
 
     @declared_attr
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
-    # region foreign keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For RelationshipTemplate many-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1231,7 +1439,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
     :vartype min_occurrences: int
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar substitution_template_mapping: Our contribution to service substitution
@@ -1245,22 +1452,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
     __private_fields__ = ['type_fk',
                           'node_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-    min_occurrences = Column(Integer, default=None)  # optional
-    max_occurrences = Column(Integer, default=None)  # optional
-
-    @declared_attr
-    def valid_source_node_types(cls):
-        return relationship.many_to_many(cls, 'type', prefix='valid_sources')
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign keys
 
     @declared_attr
@@ -1275,6 +1466,51 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     # endregion
 
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def capabilities(cls):
+        return relationship.one_to_many(cls, 'capability')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def valid_source_node_types(cls):
+        return relationship.many_to_many(cls, 'type', prefix='valid_sources')
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+    min_occurrences = Column(Integer, default=None)  # optional
+    max_occurrences = Column(Integer, default=None)  # optional
+
     def satisfies_requirement(self,
                               source_node_template,
                               requirement,
@@ -1360,7 +1596,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
     :vartype inputs: {basestring: :class:`Parameter`}
     :ivar operation_templates: Operations
     :vartype operation_templates: {basestring: :class:`OperationTemplate`}
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar group_template: Containing group template
@@ -1378,19 +1613,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
                           'group_template_fk',
                           'relationship_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def operation_templates(cls):
-        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
 
     # region foreign keys
 
@@ -1416,6 +1638,57 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     # endregion
 
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def interfaces(cls):
+        return relationship.one_to_many(cls, 'interface')
+
+    @declared_attr
+    def operation_templates(cls):
+        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.many_to_one(cls, 'relationship_template')
+
+    @declared_attr
+    def group_template(cls):
+        return relationship.many_to_one(cls, 'group_template')
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1479,7 +1752,6 @@ class OperationTemplateBase(TemplateModelMixin):
     :vartype max_retries: int
     :ivar retry_interval: Interval between retries (in seconds)
     :vartype retry_interval: int
-
     :ivar interface_template: Containing interface template
     :vartype interface_template: :class:`InterfaceTemplate`
     :ivar service_template: Containing service template
@@ -1496,21 +1768,6 @@ class OperationTemplateBase(TemplateModelMixin):
 
     description = Column(Text)
 
-    @declared_attr
-    def plugin_specification(cls):
-        return relationship.one_to_one(cls, 'plugin_specification')
-
-    implementation = Column(Text)
-    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    executor = Column(Text)
-    max_retries = Column(Integer)
-    retry_interval = Column(Integer)
-
     # region foreign keys
 
     @declared_attr
@@ -1530,6 +1787,53 @@ class OperationTemplateBase(TemplateModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def plugin_specification(cls):
+        return relationship.one_to_one(
+            cls, 'plugin_specification', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def operations(cls):
+        return relationship.one_to_many(cls, 'operation')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
+    @declared_attr
+    def interface_template(cls):
+        return relationship.many_to_one(cls, 'interface_template')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    implementation = Column(Text)
+    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
+    executor = Column(Text)
+    max_retries = Column(Integer)
+    retry_interval = Column(Integer)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1604,7 +1908,6 @@ class ArtifactTemplateBase(TemplateModelMixin):
     :vartype repository_credential: {basestring: basestring}
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar artifacts: Instantiated artifacts
@@ -1616,20 +1919,6 @@ class ArtifactTemplateBase(TemplateModelMixin):
     __private_fields__ = ['type_fk',
                           'node_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-    source_path = Column(Text)
-    target_path = Column(Text)
-    repository_url = Column(Text)
-    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign keys
 
     @declared_attr
@@ -1644,6 +1933,48 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def artifacts(cls):
+        return relationship.one_to_many(cls, 'artifact')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+    source_path = Column(Text)
+    target_path = Column(Text)
+    repository_url = Column(Text)
+    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
+
     @property
     def as_raw(self):
         return collections.OrderedDict((

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/tests/orchestrator/context/test_operation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_operation.py b/tests/orchestrator/context/test_operation.py
index 6721b29..f55b83e 100644
--- a/tests/orchestrator/context/test_operation.py
+++ b/tests/orchestrator/context/test_operation.py
@@ -353,10 +353,10 @@ def _assert_loggins(ctx, inputs):
     tasks = ctx.model.task.list()
     assert len(tasks) == 1
     task = tasks[0]
-    assert task.logs.count() == 4
+    assert len(task.logs) == 4
 
     logs = ctx.model.log.list()
-    assert len(logs) == execution.logs.count() == 6
+    assert len(logs) == len(execution.logs) == 6
     assert set(logs) == set(execution.logs)
 
     assert all(l.execution == execution for l in logs)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
----------------------------------------------------------------------
diff --git a/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml b/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
index b950fa4..3b4f371 100644
--- a/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
+++ b/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
@@ -33,7 +33,6 @@ imports:
   - types/mongodb.yaml
   - types/nginx.yaml
   - aria-1.0
-
 dsl_definitions:
 
   default_openstack_credential: &DEFAULT_OPENSTACK_CREDENTIAL



[3/3] incubator-ariatosca git commit: Add status-related methods to the Execution, Task and Node models

Posted by av...@apache.org.
Add status-related methods to the Execution, Task and Node models

We are adding these methods so it will be easier to filter those models
from storage according to their status, and to not make use of the their
`status` constants outside of the models themselves.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/02fedd92
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/02fedd92
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/02fedd92

Branch: refs/heads/ARIA-133-Add-status-related-methods-to-Execution-Task-and-Node-models
Commit: 02fedd928367d85b589b10c6c62a91f124b917d5
Parents: 2de0497
Author: Avia Efrat <av...@gigaspaces.com>
Authored: Tue Mar 28 12:51:42 2017 +0300
Committer: Avia Efrat <av...@gigaspaces.com>
Committed: Tue Mar 28 15:08:33 2017 +0300

----------------------------------------------------------------------
 aria/modeling/orchestration.py             | 16 ++++++++++++----
 aria/modeling/service_instance.py          |  3 ++-
 aria/orchestrator/workflows/core/engine.py |  7 +++----
 3 files changed, 17 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/02fedd92/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index a13ae87..b35b293 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -69,7 +69,6 @@ class ExecutionBase(ModelMixin):
 
     STATES = [TERMINATED, FAILED, CANCELLED, PENDING, STARTED, CANCELLING, FORCE_CANCELLING]
     END_STATES = [TERMINATED, FAILED, CANCELLED]
-    ACTIVE_STATES = [state for state in STATES if state not in END_STATES]
 
     VALID_TRANSITIONS = {
         PENDING: [STARTED, CANCELLED],
@@ -102,6 +101,12 @@ class ExecutionBase(ModelMixin):
     status = Column(Enum(*STATES, name='execution_status'), default=PENDING)
     workflow_name = Column(Text)
 
+    def has_ended(self):
+        return self.status in self.END_STATES
+
+    def is_active(self):
+        return not self.has_ended()
+
     @declared_attr
     def logs(cls):
         return relationship.one_to_many(cls, 'log')
@@ -240,9 +245,6 @@ class TaskBase(ModelMixin):
         FAILED,
     )
 
-    WAIT_STATES = [PENDING, RETRYING]
-    END_STATES = [SUCCESS, FAILED]
-
     RUNS_ON_SOURCE = 'source'
     RUNS_ON_TARGET = 'target'
     RUNS_ON_NODE = 'node'
@@ -288,6 +290,12 @@ class TaskBase(ModelMixin):
     implementation = Column(String)
     _runs_on = Column(Enum(*RUNS_ON, name='runs_on'), name='runs_on')
 
+    def has_ended(self):
+        return self.status in [self.SUCCESS, self.FAILED]
+
+    def is_waiting(self):
+        return not self.has_ended()
+
     @property
     def runs_on(self):
         if self._runs_on == self.RUNS_ON_NODE:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/02fedd92/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index e2e5ae0..80828b1 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -417,7 +417,8 @@ class NodeBase(InstanceModelMixin):
         except KeyError:
             return None
 
-    # region foreign_keys
+    def not_deleted_or_errored(self):
+        return self.state not in [self.DELETED, self.ERROR]
 
     @declared_attr
     def type_fk(cls):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/02fedd92/aria/orchestrator/workflows/core/engine.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/engine.py b/aria/orchestrator/workflows/core/engine.py
index fa4550d..3228934 100644
--- a/aria/orchestrator/workflows/core/engine.py
+++ b/aria/orchestrator/workflows/core/engine.py
@@ -88,12 +88,11 @@ class Engine(logger.LoggerMixin):
     def _executable_tasks(self):
         now = datetime.utcnow()
         return (task for task in self._tasks_iter()
-                if task.status in models.Task.WAIT_STATES and
-                task.due_at <= now and
+                if task.is_waiting() and task.due_at <= now and
                 not self._task_has_dependencies(task))
 
     def _ended_tasks(self):
-        return (task for task in self._tasks_iter() if task.status in models.Task.END_STATES)
+        return (task for task in self._tasks_iter() if task.has_ended)
 
     def _task_has_dependencies(self, task):
         return len(self._execution_graph.pred.get(task.id, {})) > 0
@@ -105,7 +104,7 @@ class Engine(logger.LoggerMixin):
         for _, data in self._execution_graph.nodes_iter(data=True):
             task = data['task']
             if isinstance(task, engine_task.OperationTask):
-                if task.model_task.status not in models.Task.END_STATES:
+                if not task.model_task.has_ended():
                     self._workflow_context.model.task.refresh(task.model_task)
             yield task
 


[2/3] incubator-ariatosca git commit: ARIA-132-Models-cascading-deletion-raises-constraint-errors

Posted by av...@apache.org.
ARIA-132-Models-cascading-deletion-raises-constraint-errors

Additional fixes:
- The relationships are now defined on both sides. we no longer use backref, but back_populates.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/2de04972
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/2de04972
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/2de04972

Branch: refs/heads/ARIA-133-Add-status-related-methods-to-Execution-Task-and-Node-models
Commit: 2de049729f5d0fff50297d25a88f5eecdcf266f9
Parents: 07cbfcd
Author: max-orlov <ma...@gigaspaces.com>
Authored: Sun Mar 26 14:13:47 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Tue Mar 28 15:01:15 2017 +0300

----------------------------------------------------------------------
 aria/.pylintrc                                  |   2 +-
 aria/modeling/orchestration.py                  |  16 +
 aria/modeling/relationship.py                   | 222 +++--
 aria/modeling/service_changes.py                |  86 +-
 aria/modeling/service_common.py                 |   4 +
 aria/modeling/service_instance.py               | 813 +++++++++++-------
 aria/modeling/service_template.py               | 823 +++++++++++++------
 tests/orchestrator/context/test_operation.py    |   4 +-
 .../node-cellar/node-cellar.yaml                |   1 -
 9 files changed, 1299 insertions(+), 672 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/.pylintrc
----------------------------------------------------------------------
diff --git a/aria/.pylintrc b/aria/.pylintrc
index 589402f..7222605 100644
--- a/aria/.pylintrc
+++ b/aria/.pylintrc
@@ -375,7 +375,7 @@ max-attributes=20
 min-public-methods=0
 
 # Maximum number of public methods for a class (see R0904).
-max-public-methods=20
+max-public-methods=50
 
 # Maximum number of boolean expressions in a if statement
 max-bool-expr=5

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index 2d58671..a13ae87 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -103,9 +103,17 @@ class ExecutionBase(ModelMixin):
     workflow_name = Column(Text)
 
     @declared_attr
+    def logs(cls):
+        return relationship.one_to_many(cls, 'log')
+
+    @declared_attr
     def service(cls):
         return relationship.many_to_one(cls, 'service')
 
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
+
     # region foreign keys
 
     @declared_attr
@@ -185,6 +193,10 @@ class PluginBase(ModelMixin):
 
     __tablename__ = 'plugin'
 
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
+
     archive_name = Column(Text, nullable=False, index=True)
     distribution = Column(Text)
     distribution_release = Column(Text)
@@ -239,6 +251,10 @@ class TaskBase(ModelMixin):
     INFINITE_RETRIES = -1
 
     @declared_attr
+    def logs(cls):
+        return relationship.one_to_many(cls, 'log')
+
+    @declared_attr
     def node(cls):
         return relationship.many_to_one(cls, 'node')
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
index 70691b3..ac1de28 100644
--- a/aria/modeling/relationship.py
+++ b/aria/modeling/relationship.py
@@ -26,9 +26,10 @@ from sqlalchemy import (
 
 from ..utils import formatting
 
+NO_BACK_POP = 'NO_BACK_POP'
 
-def foreign_key(other_table,
-                nullable=False):
+
+def foreign_key(other_table, nullable=False):
     """
     Declare a foreign key property, which will also create a foreign key column in the table with
     the name of the property. By convention the property name should end in "_fk".
@@ -54,9 +55,7 @@ def foreign_key(other_table,
                   nullable=nullable)
 
 
-def one_to_one_self(model_class,
-                    fk,
-                    relationship_kwargs=None):
+def one_to_one_self(model_class, fk):
     """
     Declare a one-to-one relationship property. The property value would be an instance of the same
     model.
@@ -69,12 +68,8 @@ def one_to_one_self(model_class,
     :type model_class: type
     :param fk: Foreign key name
     :type fk: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
     """
 
-    relationship_kwargs = relationship_kwargs or {}
-
     remote_side = '{model_class}.{remote_column}'.format(
         model_class=model_class.__name__,
         remote_column=model_class.id_column_name()
@@ -85,20 +80,18 @@ def one_to_one_self(model_class,
         model_class=model_class.__name__,
         column=fk
     )
-
-    return relationship(
-        _get_class_for_table(model_class, model_class.__tablename__).__name__,
-        primaryjoin=primaryjoin,
-        remote_side=remote_side,
-        post_update=True,
-        **relationship_kwargs
+    return _relationship(
+        model_class,
+        model_class.__tablename__,
+        relationship_kwargs={
+            'primaryjoin': primaryjoin,
+            'remote_side': remote_side,
+            'post_update': True
+        }
     )
 
 
-def one_to_many_self(model_class,
-                     fk,
-                     dict_key=None,
-                     relationship_kwargs=None):
+def one_to_many_self(model_class, fk, dict_key=None):
     """
     Declare a one-to-many relationship property. The property value would be a list or dict of
     instances of the same model.
@@ -114,28 +107,24 @@ def one_to_many_self(model_class,
     :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
                      be a list
     :type dict_key: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
     """
-
-    relationship_kwargs = relationship_kwargs or {}
-
-    relationship_kwargs.setdefault('remote_side', '{model_class}.{remote_column}'.format(
-        model_class=model_class.__name__,
-        remote_column=fk
-    ))
-
-    return _relationship(model_class, model_class.__tablename__, None, relationship_kwargs,
-                         other_property=False, dict_key=dict_key)
+    return _relationship(
+        model_class,
+        model_class.__tablename__,
+        relationship_kwargs={
+            'remote_side': '{model_class}.{remote_column}'.format(
+                model_class=model_class.__name__, remote_column=fk)
+        },
+        back_populates=False,
+        dict_key=dict_key
+    )
 
 
 def one_to_one(model_class,
                other_table,
                fk=None,
                other_fk=None,
-               other_property=None,
-               relationship_kwargs=None,
-               backref_kwargs=None):
+               back_populates=None):
     """
     Declare a one-to-one relationship property. The property value would be an instance of the other
     table's model.
@@ -154,26 +143,25 @@ def one_to_one(model_class,
     :type fk: basestring
     :param other_fk: Foreign key name at the other table (no need specify if there's no ambiguity)
     :type other_fk: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
+    :param back_populates: Override name of matching many-to-many property at other table; set to
+                       false to disable
+    :type back_populates: basestring|bool
     """
+    if back_populates is None:
+        back_populates = model_class.__tablename__
 
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', False)
-
-    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
-                         other_property, fk=fk, other_fk=other_fk)
+    return _relationship(model_class,
+                         other_table,
+                         fk=fk,
+                         back_populates=back_populates,
+                         other_fk=other_fk)
 
 
 def one_to_many(model_class,
                 child_table,
                 child_fk=None,
                 dict_key=None,
-                child_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
+                back_populates=None):
     """
     Declare a one-to-many relationship property. The property value would be a list or dict of
     instances of the child table's model.
@@ -194,29 +182,25 @@ def one_to_many(model_class,
     :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
                      be a list
     :type dict_key: basestring
-    :param child_property: Override name of matching many-to-one property at child table; set to
+    :param back_populates: Override name of matching many-to-one property at child table; set to
                            false to disable
-    :type child_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
+    :type back_populates: basestring|bool
     """
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', False)
-
-    return _relationship(model_class, child_table, backref_kwargs, relationship_kwargs,
-                         child_property, other_fk=child_fk, dict_key=dict_key)
+    if back_populates is None:
+        back_populates = model_class.__tablename__
+    return _relationship(
+        model_class,
+        child_table,
+        back_populates=back_populates,
+        other_fk=child_fk,
+        dict_key=dict_key)
 
 
 def many_to_one(model_class,
                 parent_table,
                 fk=None,
                 parent_fk=None,
-                parent_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
+                back_populates=None):
     """
     Declare a many-to-one relationship property. The property value would be an instance of the
     parent table's model.
@@ -236,34 +220,25 @@ def many_to_one(model_class,
     :type parent_table: basestring
     :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
     :type fk: basestring
-    :param parent_property: Override name of matching one-to-many property at parent table; set to
+    :param back_populates: Override name of matching one-to-many property at parent table; set to
                             false to disable
-    :type parent_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
+    :type back_populates: basestring|bool
     """
+    if back_populates is None:
+        back_populates = formatting.pluralize(model_class.__tablename__)
 
-    if parent_property is None:
-        parent_property = formatting.pluralize(model_class.__tablename__)
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', True)
-    backref_kwargs.setdefault('lazy', 'dynamic')
-    backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
-
-    return _relationship(model_class, parent_table, backref_kwargs, relationship_kwargs,
-                         parent_property, fk=fk, other_fk=parent_fk)
+    return _relationship(model_class,
+                         parent_table,
+                         back_populates=back_populates,
+                         fk=fk,
+                         other_fk=parent_fk)
 
 
 def many_to_many(model_class,
                  other_table,
                  prefix=None,
                  dict_key=None,
-                 other_property=None,
-                 relationship_kwargs=None,
-                 backref_kwargs=None):
+                 other_property=None):
     """
     Declare a many-to-many relationship property. The property value would be a list or dict of
     instances of the other table's model.
@@ -280,8 +255,8 @@ def many_to_many(model_class,
 
     :param model_class: The class in which this relationship will be declared
     :type model_class: type
-    :param parent_table: Parent table name
-    :type parent_table: basestring
+    :param other_table: Parent table name
+    :type other_table: basestring
     :param prefix: Optional prefix for extra table name as well as for ``other_property``
     :type prefix: basestring
     :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
@@ -290,10 +265,6 @@ def many_to_many(model_class,
     :param other_property: Override name of matching many-to-many property at other table; set to
                            false to disable
     :type other_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
     """
 
     this_table = model_class.__tablename__
@@ -303,69 +274,68 @@ def many_to_many(model_class,
     other_column_name = '{0}_id'.format(other_table)
     other_foreign_key = '{0}.id'.format(other_table)
 
-    secondary_table = '{0}_{1}'.format(this_table, other_table)
+    secondary_table_name = '{0}_{1}'.format(this_table, other_table)
 
     if prefix is not None:
-        secondary_table = '{0}_{1}'.format(prefix, secondary_table)
+        secondary_table_name = '{0}_{1}'.format(prefix, secondary_table_name)
         if other_property is None:
             other_property = '{0}_{1}'.format(prefix, formatting.pluralize(this_table))
 
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', True)
-
-    relationship_kwargs = relationship_kwargs or {}
-    relationship_kwargs.setdefault('secondary', _get_secondary_table(
+    secondary_table = _get_secondary_table(
         model_class.metadata,
-        secondary_table,
+        secondary_table_name,
         this_column_name,
         other_column_name,
         this_foreign_key,
         other_foreign_key
-    ))
+    )
 
-    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
-                         other_property, dict_key=dict_key)
+    return _relationship(
+        model_class,
+        other_table,
+        relationship_kwargs={'secondary': secondary_table},
+        backref_kwargs={'name': other_property, 'uselist': True} if other_property else None,
+        dict_key=dict_key
+    )
 
 
-def _relationship(model_class, other_table, backref_kwargs, relationship_kwargs, other_property,
-                  fk=None, other_fk=None, dict_key=None):
+def _relationship(model_class,
+                  other_table_name,
+                  back_populates=None,
+                  backref_kwargs=None,
+                  relationship_kwargs=None,
+                  fk=None,
+                  other_fk=None,
+                  dict_key=None):
     relationship_kwargs = relationship_kwargs or {}
 
     if fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(
-                                               model_class,
-                                               model_class.__tablename__),
-                                           fk))
+        relationship_kwargs.setdefault(
+            'foreign_keys',
+            lambda: getattr(_get_class_for_table(model_class, model_class.__tablename__), fk)
+        )
 
     elif other_fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(
-                                               model_class,
-                                               other_table),
-                                           other_fk))
+        relationship_kwargs.setdefault(
+            'foreign_keys',
+            lambda: getattr(_get_class_for_table(model_class, other_table_name), other_fk)
+        )
 
     if dict_key:
         relationship_kwargs.setdefault('collection_class',
                                        attribute_mapped_collection(dict_key))
 
-    if other_property is False:
-        # No backref
-        return relationship(
-            lambda: _get_class_for_table(model_class, other_table),
-            **relationship_kwargs
-        )
+    if backref_kwargs:
+        assert back_populates is None
+        return relationship(lambda: _get_class_for_table(model_class, other_table_name),
+                            backref=backref(**backref_kwargs),
+                            **relationship_kwargs
+                           )
     else:
-        if other_property is None:
-            other_property = model_class.__tablename__
-        backref_kwargs = backref_kwargs or {}
-        return relationship(
-            lambda: _get_class_for_table(model_class, other_table),
-            backref=backref(other_property, **backref_kwargs),
-            **relationship_kwargs
-        )
+        if back_populates is not NO_BACK_POP:
+            relationship_kwargs['back_populates'] = back_populates
+        return relationship(lambda: _get_class_for_table(model_class, other_table_name),
+                            **relationship_kwargs)
 
 
 def _get_class_for_table(model_class, tablename):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index a33e6ae..b1a75a2 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -42,9 +42,6 @@ class ServiceUpdateBase(ModelMixin):
     """
     Deployment update model representation.
     """
-
-    steps = None
-
     __tablename__ = 'service_update'
 
     __private_fields__ = ['service_fk',
@@ -60,14 +57,6 @@ class ServiceUpdateBase(ModelMixin):
     modified_entity_ids = Column(Dict)
     state = Column(Text)
 
-    @declared_attr
-    def execution(cls):
-        return relationship.many_to_one(cls, 'execution')
-
-    @declared_attr
-    def service(cls):
-        return relationship.many_to_one(cls, 'service', parent_property='updates')
-
     # region foreign keys
 
     @declared_attr
@@ -94,6 +83,34 @@ class ServiceUpdateBase(ModelMixin):
 
     # endregion
 
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def steps(cls):
+        return relationship.one_to_many(cls, 'service_update_step')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def execution(cls):
+        return relationship.one_to_one(cls, 'execution', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service', back_populates='updates')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     def to_dict(self, suppress_error=False, **kwargs):
         dep_update_dict = super(ServiceUpdateBase, self).to_dict(suppress_error)     #pylint: disable=no-member
         # Taking care of the fact the DeploymentSteps are _BaseModels
@@ -133,10 +150,6 @@ class ServiceUpdateStepBase(ModelMixin):
     entity_id = Column(Text, nullable=False)
     entity_type = Column(Enum(*ENTITY_TYPES, name='entity_type'), nullable=False)
 
-    @declared_attr
-    def service_update(cls):
-        return relationship.many_to_one(cls, 'service_update', parent_property='steps')
-
     # region foreign keys
 
     @declared_attr
@@ -154,6 +167,26 @@ class ServiceUpdateStepBase(ModelMixin):
 
     # endregion
 
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_update(cls):
+        return relationship.many_to_one(cls, 'service_update', back_populates='steps')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     def __hash__(self):
         return hash((getattr(self, self.id_column_name()), self.entity_id))
 
@@ -206,10 +239,6 @@ class ServiceModificationBase(ModelMixin):
     nodes = Column(Dict)
     status = Column(Enum(*STATES, name='service_modification_status'))
 
-    @declared_attr
-    def service(cls):
-        return relationship.many_to_one(cls, 'service', parent_property='modifications')
-
     # region foreign keys
 
     @declared_attr
@@ -226,3 +255,22 @@ class ServiceModificationBase(ModelMixin):
         return association_proxy('service', cls.name_column_name())
 
     # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service', back_populates='modifications')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index d6b1f33..48c3170 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -275,6 +275,10 @@ class PluginSpecificationBase(TemplateModelMixin):
 
     # endregion
 
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
     @property
     def as_raw(self):
         return collections.OrderedDict((

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 1e18db0..e2e5ae0 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -36,7 +36,7 @@ from . import (
 )
 
 
-class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
+class ServiceBase(InstanceModelMixin):
     """
     A service is usually an instance of a :class:`ServiceTemplate`.
 
@@ -71,12 +71,10 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :vartype created_at: :class:`datetime.datetime`
     :ivar updated_at: Update timestamp
     :vartype updated_at: :class:`datetime.datetime`
-
     :ivar permalink: ??
     :vartype permalink: basestring
     :ivar scaling_groups: ??
     :vartype scaling_groups: {}
-
     :ivar modifications: Modifications of this service
     :vartype modifications: [:class:`ServiceModification`]
     :ivar updates: Updates of this service
@@ -91,16 +89,53 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
                           'service_template_fk',
                           'service_template_name']
 
+    # region foreign keys
+
     @declared_attr
-    def service_template(cls):
-        return relationship.many_to_one(cls, 'service_template')
+    def substitution_fk(cls):
+        """Service one-to-one to Substitution"""
+        return relationship.foreign_key('substitution', nullable=True)
 
-    description = Column(Text)
+    @declared_attr
+    def service_template_fk(cls):
+        """For Service many-to-one to ServiceTemplate"""
+        return relationship.foreign_key('service_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
 
     @declared_attr
-    def meta_data(cls):
-        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
-        return relationship.many_to_many(cls, 'metadata', dict_key='name')
+    def service_template_name(cls):
+        """Required for use by SQLAlchemy queries"""
+        return association_proxy('service_template', 'name')
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def substitution(cls):
+        return relationship.one_to_one(cls, 'substitution', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+    @declared_attr
+    def updates(cls):
+        return relationship.one_to_many(cls, 'service_update')
+
+    @declared_attr
+    def modifications(cls):
+        return relationship.one_to_many(cls, 'service_modification')
+
+    @declared_attr
+    def executions(cls):
+        return relationship.one_to_many(cls, 'execution')
+
+    @declared_attr
+    def operations(cls):
+        return relationship.one_to_many(cls, 'operation')
 
     @declared_attr
     def nodes(cls):
@@ -115,8 +150,24 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         return relationship.one_to_many(cls, 'policy', dict_key='name')
 
     @declared_attr
-    def substitution(cls):
-        return relationship.one_to_one(cls, 'substitution')
+    def workflows(cls):
+        return relationship.one_to_many(cls, 'operation', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
+    # endregion
+
+    # region many_to_many relationships
+    @declared_attr
+    def meta_data(cls):
+        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
+        return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
     def inputs(cls):
@@ -127,13 +178,13 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
-    def workflows(cls):
-        return relationship.one_to_many(cls, 'operation', dict_key='name')
-
-    @declared_attr
     def plugin_specifications(cls):
         return relationship.many_to_many(cls, 'plugin_specification', dict_key='name')
 
+    # endregion
+
+    description = Column(Text)
+
     created_at = Column(DateTime, nullable=False, index=True)
     updated_at = Column(DateTime)
 
@@ -144,29 +195,6 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     # endregion
 
-    # region foreign keys
-
-    @declared_attr
-    def substitution_fk(cls):
-        """Service one-to-one to Substitution"""
-        return relationship.foreign_key('substitution', nullable=True)
-
-    @declared_attr
-    def service_template_fk(cls):
-        """For Service many-to-one to ServiceTemplate"""
-        return relationship.foreign_key('service_template', nullable=True)
-
-    # endregion
-
-    # region association proxies
-
-    @declared_attr
-    def service_template_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service_template', 'name')
-
-    # endregion
-
     def satisfy_requirements(self):
         satisfied = True
         for node in self.nodes.itervalues():
@@ -290,7 +318,7 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
                         self._dump_graph_node(target_node)
 
 
-class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
+class NodeBase(InstanceModelMixin):
     """
     Usually an instance of a :class:`NodeTemplate`.
 
@@ -318,7 +346,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :vartype inbound_relationships: [:class:`Relationship`]
     :ivar host: Host node (can be self)
     :vartype host: :class:`Node`
-
     :ivar runtime_properties: TODO: should be replaced with attributes
     :vartype runtime_properties: {}
     :ivar scaling_groups: ??
@@ -327,7 +354,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :vartype state: string
     :ivar version: Used by `aria.storage.instrumentation`
     :vartype version: int
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     :ivar groups: We are a member of these groups
@@ -391,19 +417,52 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         except KeyError:
             return None
 
+    # region foreign_keys
+
     @declared_attr
-    def node_template(cls):
-        return relationship.many_to_one(cls, 'node_template')
+    def type_fk(cls):
+        """For Node many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def host_fk(cls):
+        """For Node one-to-one to Node"""
+        return relationship.foreign_key('node', nullable=True)
 
-    description = Column(Text)
+    @declared_attr
+    def service_fk(cls):
+        """For Service one-to-many to Node"""
+        return relationship.foreign_key('service')
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def node_template_fk(cls):
+        """For Node many-to-one to NodeTemplate"""
+        return relationship.foreign_key('node_template')
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_name(cls):
+        """Required for use by SQLAlchemy queries"""
+        return association_proxy('service', 'name')
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def host(cls):
+        return relationship.one_to_one_self(cls, 'host_fk')
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
 
     @declared_attr
     def interfaces(cls):
@@ -419,20 +478,40 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     @declared_attr
     def outbound_relationships(cls):
-        return relationship.one_to_many(cls, 'relationship', child_fk='source_node_fk',
-                                        child_property='source_node')
+        return relationship.one_to_many(
+            cls, 'relationship', child_fk='source_node_fk', back_populates='source_node')
 
     @declared_attr
     def inbound_relationships(cls):
-        return relationship.one_to_many(cls, 'relationship', child_fk='target_node_fk',
-                                        child_property='target_node')
+        return relationship.one_to_many(
+            cls, 'relationship', child_fk='target_node_fk', back_populates='target_node')
+
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def host(cls):
-        return relationship.one_to_one_self(cls, 'host_fk')
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
-    # region orchestration
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
+    # endregion
+
+    # region many_to_many relationships
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
     runtime_properties = Column(modeling_types.Dict)
     scaling_groups = Column(modeling_types.List)
     state = Column(Enum(*STATES, name='node_state'), nullable=False, default=INITIAL)
@@ -454,41 +533,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
             return host_ip_property.value
         return None
 
-    # endregion
-
-    # region foreign_keys
-
-    @declared_attr
-    def type_fk(cls):
-        """For Node many-to-one to Type"""
-        return relationship.foreign_key('type')
-
-    @declared_attr
-    def host_fk(cls):
-        """For Node one-to-one to Node"""
-        return relationship.foreign_key('node', nullable=True)
-
-    @declared_attr
-    def service_fk(cls):
-        """For Service one-to-many to Node"""
-        return relationship.foreign_key('service')
-
-    @declared_attr
-    def node_template_fk(cls):
-        """For Node many-to-one to NodeTemplate"""
-        return relationship.foreign_key('node_template', nullable=True)
-
-    # endregion
-
-    # region association proxies
-
-    @declared_attr
-    def service_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', 'name')
-
-    # endregion
-
     def satisfy_requirements(self):
         node_template = self.node_template
         satisfied = True
@@ -513,7 +557,7 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         from . import models
         context = ConsumptionContext.get_thread_local()
         # Find target nodes
-        target_nodes = target_node_template.nodes.all()
+        target_nodes = target_node_template.nodes
         if target_nodes:
             target_node = None
             target_capability = None
@@ -621,6 +665,7 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
             utils.dump_dict_values(self.capabilities, 'Capabilities')
             utils.dump_list_values(self.outbound_relationships, 'Relationships')
 
+
 class GroupBase(InstanceModelMixin):
     """
     Usually an instance of a :class:`GroupTemplate`.
@@ -639,7 +684,6 @@ class GroupBase(InstanceModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interface`}
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     :ivar policies: Policies enacted on this group
@@ -648,51 +692,73 @@ class GroupBase(InstanceModelMixin):
 
     __tablename__ = 'group'
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'group_template_fk']
+    __private_fields__ = ['type_fk', 'service_fk', 'group_template_fk']
 
-    @declared_attr
-    def group_template(cls):
-        return relationship.many_to_one(cls, 'group_template')
+    # region foreign_keys
 
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
+    def type_fk(cls):
+        """For Group many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def nodes(cls):
-        return relationship.many_to_many(cls, 'node')
+    def service_fk(cls):
+        """For Service one-to-many to Group"""
+        return relationship.foreign_key('service')
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def group_template_fk(cls):
+        """For Group many-to-one to GroupTemplate"""
+        return relationship.foreign_key('group_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
     def interfaces(cls):
         return relationship.one_to_many(cls, 'interface', dict_key='name')
 
-    # region foreign_keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For Group many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
     @declared_attr
-    def service_fk(cls):
-        """For Service one-to-many to Group"""
-        return relationship.foreign_key('service')
+    def group_template(cls):
+        return relationship.many_to_one(cls, 'group_template')
 
     @declared_attr
-    def group_template_fk(cls):
-        """For Group many-to-one to GroupTemplate"""
-        return relationship.foreign_key('group_template', nullable=True)
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def nodes(cls):
+        return relationship.many_to_many(cls, 'node')
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -740,58 +806,79 @@ class PolicyBase(InstanceModelMixin):
     :vartype groups: [:class:`Group`]
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     """
 
     __tablename__ = 'policy'
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'policy_template_fk']
+    __private_fields__ = ['type_fk', 'service_fk', 'policy_template_fk']
 
-    @declared_attr
-    def policy_template(cls):
-        return relationship.many_to_one(cls, 'policy_template')
+    # region foreign_keys
 
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def type_fk(cls):
+        """For Policy many-to-one to Type"""
+        return relationship.foreign_key('type')
 
-    description = Column(Text)
+    @declared_attr
+    def service_fk(cls):
+        """For Service one-to-many to Policy"""
+        return relationship.foreign_key('service')
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def policy_template_fk(cls):
+        """For Policy many-to-one to PolicyTemplate"""
+        return relationship.foreign_key('policy_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def nodes(cls):
-        return relationship.many_to_many(cls, 'node')
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
     @declared_attr
-    def groups(cls):
-        return relationship.many_to_many(cls, 'group')
+    def policy_template(cls):
+        return relationship.many_to_one(cls, 'policy_template')
 
-    # region foreign_keys
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For Policy many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
-    def service_fk(cls):
-        """For Service one-to-many to Policy"""
-        return relationship.foreign_key('service')
+    def nodes(cls):
+        return relationship.many_to_many(cls, 'node')
 
     @declared_attr
-    def policy_template_fk(cls):
-        """For Policy many-to-one to PolicyTemplate"""
-        return relationship.foreign_key('policy_template', nullable=True)
+    def groups(cls):
+        return relationship.many_to_many(cls, 'group')
 
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -835,7 +922,6 @@ class SubstitutionBase(InstanceModelMixin):
     :vartype node_type: :class:`Type`
     :ivar mappings: Requirement and capability mappings
     :vartype mappings: {basestring: :class:`SubstitutionTemplate`}
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     """
@@ -845,29 +931,53 @@ class SubstitutionBase(InstanceModelMixin):
     __private_fields__ = ['node_type_fk',
                           'substitution_template_fk']
 
+    # region foreign_keys
+
     @declared_attr
-    def substitution_template(cls):
-        return relationship.many_to_one(cls, 'substitution_template')
+    def node_type_fk(cls):
+        """For Substitution many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def node_type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def substitution_template_fk(cls):
+        """For Substitution many-to-one to SubstitutionTemplate"""
+        return relationship.foreign_key('substitution_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
     def mappings(cls):
         return relationship.one_to_many(cls, 'substitution_mapping', dict_key='name')
 
-    # region foreign_keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def node_type_fk(cls):
-        """For Substitution many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def service(cls):
+        return relationship.one_to_one(cls, 'service', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
-    def substitution_template_fk(cls):
-        """For Substitution many-to-one to SubstitutionTemplate"""
-        return relationship.foreign_key('substitution_template', nullable=True)
+    def substitution_template(cls):
+        return relationship.many_to_one(cls, 'substitution_template')
+
+    @declared_attr
+    def node_type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
 
     # endregion
 
@@ -907,7 +1017,6 @@ class SubstitutionMappingBase(InstanceModelMixin):
     :vartype capability: :class:`Capability`
     :ivar requirement_template: Requirement template in the node template
     :vartype requirement_template: :class:`RequirementTemplate`
-
     :ivar substitution: Containing substitution
     :vartype substitution: :class:`Substitution`
     """
@@ -919,18 +1028,6 @@ class SubstitutionMappingBase(InstanceModelMixin):
                           'capability_fk',
                           'requirement_template_fk']
 
-    @declared_attr
-    def node(cls):
-        return relationship.one_to_one(cls, 'node')
-
-    @declared_attr
-    def capability(cls):
-        return relationship.one_to_one(cls, 'capability')
-
-    @declared_attr
-    def requirement_template(cls):
-        return relationship.one_to_one(cls, 'requirement_template')
-
     # region foreign keys
 
     @declared_attr
@@ -955,6 +1052,43 @@ class SubstitutionMappingBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def substitution(cls):
+        return relationship.many_to_one(cls, 'substitution', back_populates='mappings')
+
+    @declared_attr
+    def node(cls):
+        return relationship.one_to_one(cls, 'node', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def capability(cls):
+        return relationship.one_to_one(cls, 'capability', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def requirement_template(cls):
+        return relationship.one_to_one(
+            cls, 'requirement_template', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1002,12 +1136,10 @@ class RelationshipBase(InstanceModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interfaces`}
-
     :ivar source_position: ??
     :vartype source_position: int
     :ivar target_position: ??
     :vartype target_position: int
-
     :ivar source_node: Source node
     :vartype source_node: :class:`Node`
     :ivar target_node: Target node
@@ -1027,37 +1159,6 @@ class RelationshipBase(InstanceModelMixin):
                           'source_node_name',
                           'target_node_name']
 
-    @declared_attr
-    def relationship_template(cls):
-        return relationship.many_to_one(cls, 'relationship_template')
-
-    @declared_attr
-    def requirement_template(cls):
-        return relationship.many_to_one(cls, 'requirement_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    @declared_attr
-    def target_capability(cls):
-        return relationship.one_to_one(cls, 'capability')
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    @declared_attr
-    def interfaces(cls):
-        return relationship.one_to_many(cls, 'interface', dict_key='name')
-
-    # region orchestration
-
-    source_position = Column(Integer) # ???
-    target_position = Column(Integer) # ???
-
-    # endregion
-
     # region foreign keys
 
     @declared_attr
@@ -1106,6 +1207,63 @@ class RelationshipBase(InstanceModelMixin):
 
     # endregion
 
+    # region one_to_one relationships
+
+    @declared_attr
+    def target_capability(cls):
+        return relationship.one_to_one(cls, 'capability', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
+
+    @declared_attr
+    def interfaces(cls):
+        return relationship.one_to_many(cls, 'interface', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def source_node(cls):
+        return relationship.many_to_one(
+            cls, 'node', fk='source_node_fk', back_populates='outbound_relationships')
+
+    @declared_attr
+    def target_node(cls):
+        return relationship.many_to_one(
+            cls, 'node', fk='target_node_fk', back_populates='inbound_relationships')
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.many_to_one(cls, 'relationship_template')
+
+    @declared_attr
+    def requirement_template(cls):
+        return relationship.many_to_one(cls, 'requirement_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    source_position = Column(Integer) # ???
+    target_position = Column(Integer) # ???
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1166,7 +1324,6 @@ class CapabilityBase(InstanceModelMixin):
     :vartype occurrences: int
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node: Containing node
     :vartype node: :class:`Node`
     :ivar relationship: Available when we are the target of a relationship
@@ -1181,22 +1338,6 @@ class CapabilityBase(InstanceModelMixin):
                           'node_fk',
                           'capability_template_fk']
 
-    @declared_attr
-    def capability_template(cls):
-        return relationship.many_to_one(cls, 'capability_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    min_occurrences = Column(Integer, default=None)
-    max_occurrences = Column(Integer, default=None)
-    occurrences = Column(Integer, default=0)
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign_keys
 
     @declared_attr
@@ -1216,6 +1357,46 @@ class CapabilityBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def capability_template(cls):
+        return relationship.many_to_one(cls, 'capability_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    min_occurrences = Column(Integer, default=None)
+    max_occurrences = Column(Integer, default=None)
+    occurrences = Column(Integer, default=0)
+
     @property
     def has_enough_relationships(self):
         if self.min_occurrences is not None:
@@ -1274,7 +1455,6 @@ class InterfaceBase(InstanceModelMixin):
     :vartype inputs: {basestring: :class:`Parameter`}
     :ivar operations: Operations
     :vartype operations: {basestring: :class:`Operation`}
-
     :ivar node: Containing node
     :vartype node: :class:`Node`
     :ivar group: Containing group
@@ -1291,24 +1471,6 @@ class InterfaceBase(InstanceModelMixin):
                           'relationship_fk',
                           'interface_template_fk']
 
-    @declared_attr
-    def interface_template(cls):
-        return relationship.many_to_one(cls, 'interface_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def operations(cls):
-        return relationship.one_to_many(cls, 'operation', dict_key='name')
-
     # region foreign_keys
 
     @declared_attr
@@ -1338,6 +1500,56 @@ class InterfaceBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def operations(cls):
+        return relationship.one_to_many(cls, 'operation', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def relationship(cls):
+        return relationship.many_to_one(cls, 'relationship')
+
+    @declared_attr
+    def group(cls):
+        return relationship.many_to_one(cls, 'group')
+
+    @declared_attr
+    def interface_template(cls):
+        return relationship.many_to_one(cls, 'interface_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1392,7 +1604,6 @@ class OperationBase(InstanceModelMixin):
     :vartype max_retries: int
     :ivar retry_interval: Interval between retries (in seconds)
     :vartype retry_interval: int
-
     :ivar interface: Containing interface
     :vartype interface: :class:`Interface`
     :ivar service: Containing service
@@ -1406,27 +1617,6 @@ class OperationBase(InstanceModelMixin):
                           'plugin_fk',
                           'operation_template_fk']
 
-    @declared_attr
-    def operation_template(cls):
-        return relationship.many_to_one(cls, 'operation_template')
-
-    description = Column(Text)
-
-    @declared_attr
-    def plugin_specification(cls):
-        return relationship.one_to_one(cls, 'plugin_specification')
-
-    implementation = Column(Text)
-    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    executor = Column(Text)
-    max_retries = Column(Integer)
-    retry_interval = Column(Integer)
-
     # region foreign_keys
 
     @declared_attr
@@ -1451,6 +1641,56 @@ class OperationBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def plugin_specification(cls):
+        return relationship.one_to_one(
+            cls, 'plugin_specification', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
+
+    @declared_attr
+    def interface(cls):
+        return relationship.many_to_one(cls, 'interface')
+
+    @declared_attr
+    def operation_template(cls):
+        return relationship.many_to_one(cls, 'operation_template')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+    implementation = Column(Text)
+    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
+    executor = Column(Text)
+    max_retries = Column(Integer)
+    retry_interval = Column(Integer)
+
+
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1517,7 +1757,6 @@ class ArtifactBase(InstanceModelMixin):
     :vartype repository_credential: {basestring: basestring}
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node: Containing node
     :vartype node: :class:`Node`
     """
@@ -1528,24 +1767,6 @@ class ArtifactBase(InstanceModelMixin):
                           'node_fk',
                           'artifact_template_fk']
 
-    @declared_attr
-    def artifact_template(cls):
-        return relationship.many_to_one(cls, 'artifact_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-    source_path = Column(Text)
-    target_path = Column(Text)
-    repository_url = Column(Text)
-    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign_keys
 
     @declared_attr
@@ -1565,6 +1786,44 @@ class ArtifactBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def artifact_template(cls):
+        return relationship.many_to_one(cls, 'artifact_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+    # endregion
+
+    # region many_to_many relationships
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    # endregion
+
+    description = Column(Text)
+    source_path = Column(Text)
+    target_path = Column(Text)
+    repository_url = Column(Text)
+    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
+
     @property
     def as_raw(self):
         return collections.OrderedDict((