def create_subclass(self, params, **kwargs): """ Subclasses the LayerSelectionResource instance's class for the given config_entity and layer. :param params Must contain a 'config_entity__id' and 'layer__id' :return: """ layer = self.resolve_layer(params) config_entity = self.resolve_config_entity(params) logger.debug( "Resolving LayerSelection for config_entity %s, layer %s" % (config_entity.key, layer.db_entity.key)) layer_selection_class = get_or_create_layer_selection_class_for_layer( layer, config_entity) # Have the LayerPublisher create the LayerSelection instance for the user if needed update_or_create_layer_selections_for_layer( layer, users=[self.resolve_user(params)]) if not layer_selection_class: raise Exception( "Layer with db_entity_key %s has no feature_class. Its LayerSelections should not be requested" % layer.db_entity_key) return get_dynamic_resource_class(self.__class__, layer_selection_class)
def create_subclass(self, params, **kwargs): land_use_definition_fixture_class = resolve_fixture_class( "built_form", "land_use_definition", ClientLandUseDefinition, settings.CLIENT) return get_dynamic_resource_class( self.__class__, land_use_definition_fixture_class)
def create_subclass(self, params, **kwargs): """ Subclasses the LayerSelectionResource instance's class for the given config_entity and layer. :param params Must contain a 'config_entity__id' and 'layer__id' :return: """ layer = self.resolve_layer(params) config_entity = self.resolve_config_entity(params) logger.debug("Resolving LayerSelection for config_entity %s, layer %s" % (config_entity.key, layer.db_entity.key)) layer_selection_class = get_or_create_layer_selection_class_for_layer(layer, config_entity) # Have the LayerPublisher create the LayerSelection instance for the user if needed update_or_create_layer_selections_for_layer(layer, users=[self.resolve_user(params)]) if not layer_selection_class: raise Exception("Layer with db_entity_key %s has no feature_class. Its LayerSelections should not be requested" % layer.db_entity_key) return get_dynamic_resource_class( self.__class__, layer_selection_class )
def resolve_resource_class(cls, model_class, related_descriptors=None, queryset=None, base_resource_class=None, object_class=None, no_cache=False, use_version_fields=False, only_abstract_resources=True, additional_fields_dict=None, is_join_query=False, limit_fields=None, for_template=False): """ Match the model_class to an existing resource class by iterating through subclasses of self.__class__ If no match occurs generate one if db_entity is specified, else None :param model_class: :param related_descriptors: Optionally provided a dictionary of related descriptors of the model_class to use to create related resource fields in the case of dynamic resource creation. If unspecified, related_descriptors are found using the base resource class's resolve_related_descriptors method :param no_cache: Don't use cached resources. Specifying queryset also prevents the cache being consulted :param use_version_fields: Special case for versioned models. Instructs the resource class creation to create dynamic fields to look in the model_class's Revisionable._version_field_dict to resolve the value of a field before looking at the database (current object) version of the field. :param additional_fields_dict. Optional dict that gives the resource class additional fields with values. This is not for related fields, rather special cases like passing the layer_selection to the FeatureResource. :param for_template: Currently just used for Features, but this indicates a template version of the resource is being sought :param is_join_query: True if the is a join query table or similar. This means that the queryset isn't actually valid yet :return: The matching or created resource """ # Never seek a cached resource if a queryset or no_cache is specified allow_caching = queryset is None and not no_cache cls.logger.info("Resolving Resource Class for model_class %s with query %s and allow_caching %s and only_abstract_resources %s and base_resource_class %s", model_class.__name__, queryset, allow_caching, only_abstract_resources, base_resource_class) if not base_resource_class and allow_caching: # Try to get a cached resource if a base_resource_class is present and we allow caching # of this resource. We never allow caching if the queryset changes from request to request # Instead we subclass the best matching existing resource class resources = FootprintResource.match_existing_resources(model_class) if len(resources) > 1: logging.warn("Too many resources for model class: %s. Resources; %s" % (model_class, resources)) if (len(resources) > 0): cls.logger.info("Found existing resource class %s for model class %s" % (resources[0], model_class)) # Done, return the existing resource return resources[0] # If we don't allow caching or no resource was found if only_abstract_resources: # See if we can match an abstract resource to be our base. # We look for the best matching resource who's model class matches or is a superclass or our model class. base_resource_classes = FootprintResource.match_existing_resources(model_class, only_abstract_resources=True) cls.logger.info("Matching abstract base resource classes: %s" % base_resource_classes) base_resource_class = base_resource_classes[0] if len(base_resource_classes)==1 else base_resource_class else: # Fist try to find a concrete one that we already created concrete_base_resource_classes = FootprintResource.match_existing_resources(model_class, allow_abstract_resources=False) if len(concrete_base_resource_classes)==1: # Found a concrete resource class that was already created for this model # If this isn't a join query we can return this resource class base_resource_class = concrete_base_resource_classes[0] if not is_join_query: return base_resource_class else: # Try to find an abstract one all_base_resource_classes = FootprintResource.match_existing_resources(model_class, only_abstract_resources=True) cls.logger.info("Matching abstract base resource classes: %s" % all_base_resource_classes) base_resource_class = all_base_resource_classes[0] if len(all_base_resource_classes)==1 else base_resource_class if is_join_query: # Join queries must pass in the limited fields from the layer_selection.result_map.result_fields limit_api_fields = limit_fields else: # Non-join queries find their fields from the model_class limit_api_fields = limited_api_fields(model_class, for_template=for_template) resource_class = base_resource_class or cls if base_resource_class: cls.logger.info("Resolved base_resource_class: %s" % base_resource_class) else: cls.logger.info("Could not resolve a base_resource_class. Using resource class %s" % cls) related_descriptors = related_descriptors or \ resource_class.resolve_related_descriptors(model_class) or \ {} cls.logger.info("Creating a resource subclass of %s for model_class %s with the following related descriptors %s" % ( resource_class, model_class, ', '.join(map_dict( lambda related_field_name, related_descriptor: related_field_name, related_descriptors )))) related_fields = merge(additional_fields_dict or {}, map_dict_to_dict( lambda related_field_name, relationship_dict: cls.related_resource_field( related_field_name, merge( dict( # This is passed in, but might be overriden in the relationship_dict use_version_fields=use_version_fields ), # Already a relationship dict relationship_dict if isinstance(relationship_dict, dict) else dict(), # Not a relationship dict, just a descriptor, wrap it dict(descriptor=relationship_dict) if not isinstance(relationship_dict, dict) else dict(), ), # Always allow cached related resource classes. # I think this is always safe no_cache=False), related_descriptors)) meta = merge( dict(fields=limit_api_fields) if limit_api_fields else dict(excludes=(resource_class.Meta.excludes if hasattr( resource_class.Meta, 'excludes') else []) + cls.dynamic_excludes( model_class)), dict(queryset=queryset, object_class=object_class) if queryset else dict()) return get_dynamic_resource_class( resource_class, model_class, # Created related fields from the related_descriptors fields=related_fields, # Optionally set the fields and queryset on the Meta class meta_fields=meta )