def create_related_field(self, field_name, related_field_configuration):
        """
            Creates a ForeignKey or ManyToMany field based on related_field_configuration
        :param field_name:
        :param related_field_configuration: A dict containing related_key or related_class_name
            related_key: the instance of the sibling key of the config_entity whose dynamic_model_class is the relation type.
                For DbEntity/Features this would be the db_entity_key and the dynamic_model_class would be its FeatureClass
                For AnalysisModule this would be the analysis module key and its dynamic class
            related_class_name: rather than related_key, any model class, such as BuiltForm, to relate to.
            single: if True this is a ForeignKey (toOne) relationship. Otherwise a ManyToMany is created
        :return: A two-item tuple. First item is the field name and the second is the field.
        """

        config_entity = ConfigEntity._subclassed_by_id(self.configuration.scope)

        # TODO temp coverage of a key name name change
        related_field_configuration['related_key'] = related_field_configuration.get('related_key', related_field_configuration.get('related_db_entity_key'))

        if related_field_configuration.get('related_key', False):
            # field name matches name of peer self.db_entity_key--get it's feature class name
            related_db_entity = get_single_value_or_none(config_entity.computed_db_entities(key=related_field_configuration['related_key']))
            # Always call with no_ensure=True since the config_entity is the same. Otherwise we'd get infinite recursion
            related_class_name_or_model = self.__class__(self.config_entity, related_db_entity, no_ensure=True).dynamic_model_class()
        elif related_field_configuration.get('related_class_name', None):
            # A model class such as BuiltForm
            related_class_name_or_model = resolve_module_attr(related_field_configuration['related_class_name'])
        else:
            raise Exception("No related_key or related_class_name found on feature_class_configuration for self.configuration.key %s" % self.configuration.key)

        logger.info('Creating %r related field for %s using %s', related_field_configuration.get('single', None) and 'single' or 'm2m',
                    field_name, related_field_configuration)
        if related_field_configuration.get('single', None):
            return [field_name,
                    models.ForeignKey(related_class_name_or_model, null=True)]
        else:
            return [field_name,
                    models.ManyToManyField(related_class_name_or_model,
                                           # Pass a custom, readable table name for the through class for ManyToMany relations
                                           db_table='"{schema}"."{table}_{field_name}"'.format(
                                               schema=config_entity.schema(),
                                               table=self.configuration.key,
                                               field_name=field_name))]
    def create_related_field(self, field_name, related_field_configuration):
        """
            Creates a ForeignKey or ManyToMany field based on related_field_configuration
        :param field_name:
        :param related_field_configuration: A dict containing related_key or related_class_name
            related_key: the instance of the sibling key of the config_entity whose dynamic_model_class is the relation type.
                For DbEntity/Features this would be the db_entity_key and the dynamic_model_class would be its FeatureClass
                For AnalysisModule this would be the analysis module key and its dynamic class
            related_class_name: rather than related_key, any model class, such as BuiltForm, to relate to.
            single: if True this is a ForeignKey (toOne) relationship. Otherwise a ManyToMany is created
        :return: A two-item tuple. First item is the field name and the second is the field.
        """

        config_entity = ConfigEntity._subclassed_by_id(self.configuration.scope)

        # TODO temp coverage of a key name name change
        related_field_configuration['related_key'] = related_field_configuration.get('related_key', related_field_configuration.get('related_db_entity_key'))

        if related_field_configuration.get('related_key', False):
            # field name matches name of peer self.db_entity_key--get it's feature class name
            related_db_entity = get_single_value_or_none(config_entity.computed_db_entities(key=related_field_configuration['related_key']))
            # Always call with no_ensure=True since the config_entity is the same. Otherwise we'd get infinite recursion
            related_class_name_or_model = self.__class__(self.config_entity, related_db_entity, no_ensure=True).dynamic_model_class()
        elif related_field_configuration.get('related_class_name', None):
            # A model class such as BuiltForm
            related_class_name_or_model = resolve_module_attr(related_field_configuration['related_class_name'])
        else:
            raise Exception("No related_key or related_class_name found on feature_class_configuration for self.configuration.key %s" % self.configuration.key)

        logger.info('Creating %r related field for %s using %s', related_field_configuration.get('single', None) and 'single' or 'm2m',
                    field_name, related_field_configuration)
        if related_field_configuration.get('single', None):
            return [field_name,
                    models.ForeignKey(related_class_name_or_model, null=True)]
        else:
            return [field_name,
                    models.ManyToManyField(related_class_name_or_model,
                                           # Pass a custom, readable table name for the through class for ManyToMany relations
                                           db_table='"{schema}"."{table}_{field_name}"'.format(
                                               schema=config_entity.schema(),
                                               table=self.configuration.key,
                                               field_name=field_name))]
 def geography_scope(self):
     return ConfigEntity._subclassed_by_id(self.configuration.geography_scope \
                                                              if self.configuration and self.configuration.key else \
                                                              self.config_entity.id)