def eagerload_includes(self, query, qs): """Use eagerload feature of sqlalchemy to optimize data retrieval for include querystring parameter :param Query query: sqlalchemy queryset :param QueryStringManager qs: a querystring manager to retrieve information from url :return Query: the query with includes eagerloaded """ for include in qs.include: joinload_object = None if '.' in include: current_schema = self.resource.schema for obj in include.split('.'): try: field = get_model_field(current_schema, obj) except Exception as e: raise InvalidInclude(str(e)) if joinload_object is None: joinload_object = joinedload(field, innerjoin=True) else: joinload_object = joinload_object.joinedload( field, innerjoin=True) related_schema_cls = get_related_schema( current_schema, obj) if isinstance(related_schema_cls, SchemaABC): related_schema_cls = related_schema_cls.__class__ else: related_schema_cls = class_registry.get_class( related_schema_cls) current_schema = related_schema_cls else: try: field = get_model_field(self.resource.schema, include) except Exception as e: raise InvalidInclude(str(e)) joinload_object = joinedload(field, innerjoin=True) query = query.options(joinload_object) return query
def include(self): """Return fields to include :return list: a list of include information """ include_param = self.qs.get('include', []) if current_app.config.get('MAX_INCLUDE_DEPTH') is not None: for include_path in include_param: if len(include_path.split('.')) > current_app.config['MAX_INCLUDE_DEPTH']: raise InvalidInclude("You can't use include through more than {} relationships" .format(current_app.config['MAX_INCLUDE_DEPTH'])) return include_param.split(',') if include_param else []
def include(self): """Return fields to include :return list: a list of include information """ include_param = self.qs.get('include', []) if current_app.config.get('MAX_INCLUDE_DEPTH') is not None: for include_path in include_param: if len(include_path.split( '.')) > current_app.config['MAX_INCLUDE_DEPTH']: raise InvalidInclude( "You can't use include through more than {} relationships" .format(current_app.config['MAX_INCLUDE_DEPTH'])) if include_param: param_results = [] for param in include_param.split(','): if current_app.config['DASHERIZE_API'] is True: param = param.replace('-', '_') param_results.append(param) return param_results return []
def compute_schema(schema_cls, default_kwargs, qs, include): """Compute a schema around compound documents and sparse fieldsets :param Schema schema_cls: the schema class :param dict default_kwargs: the schema default kwargs :param QueryStringManager qs: qs :param list include: the relation field to include data from :return Schema schema: the schema computed """ # manage include_data parameter of the schema schema_kwargs = default_kwargs schema_kwargs['include_data'] = tuple() # collect sub-related_includes related_includes = {} if include: for include_path in include: field = include_path.split('.')[0] if field not in schema_cls._declared_fields: raise InvalidInclude("{} has no attribute {}".format( schema_cls.__name__, field)) elif not isinstance(schema_cls._declared_fields[field], Relationship): raise InvalidInclude( "{} is not a relationship attribute of {}".format( field, schema_cls.__name__)) schema_kwargs['include_data'] += (field, ) if field not in related_includes: related_includes[field] = [] if '.' in include_path: related_includes[field] += [ '.'.join(include_path.split('.')[1:]) ] # make sure id field is in only parameter unless marshamllow will raise an Exception if schema_kwargs.get( 'only') is not None and 'id' not in schema_kwargs['only']: schema_kwargs['only'] += ('id', ) # create base schema instance schema = schema_cls(**schema_kwargs) # manage sparse fieldsets if schema.opts.type_ in qs.fields: tmp_only = set(schema.declared_fields.keys()) & set( qs.fields[schema.opts.type_]) if schema.only: tmp_only &= set(schema.only) schema.only = tuple(tmp_only) # make sure again that id field is in only parameter unless marshamllow will raise an Exception if schema.only is not None and 'id' not in schema.only: schema.only += ('id', ) # manage compound documents if include: for include_path in include: field = include_path.split('.')[0] relation_field = schema.declared_fields[field] related_schema_cls = schema.declared_fields[field].__dict__[ '_Relationship__schema'] related_schema_kwargs = {} if 'context' in default_kwargs: related_schema_kwargs['context'] = default_kwargs['context'] if isinstance(related_schema_cls, SchemaABC): related_schema_kwargs['many'] = related_schema_cls.many related_schema_cls = related_schema_cls.__class__ if isinstance(related_schema_cls, str): related_schema_cls = class_registry.get_class( related_schema_cls) related_schema = compute_schema(related_schema_cls, related_schema_kwargs, qs, related_includes[field] or None) relation_field.__dict__['_Relationship__schema'] = related_schema return schema