def apply_nested_fields(self, data, obj): nested_fields_to_apply = [] nested_fields = get_nested_fields(self.resource.schema, model_field=True) for key, value in data.items(): if key in nested_fields: nested_field_inspection = inspect(getattr(obj.__class__, key)) if not isinstance(nested_field_inspection, QueryableAttribute): raise InvalidType("Unrecognized nested field type: not a queryable attribute.") if isinstance(nested_field_inspection.property, RelationshipProperty): nested_model = getattr(obj.__class__, key).property.mapper.class_ if isinstance(value, list): nested_objects = [] for identifier in value: nested_object = nested_model(**identifier) nested_objects.append(nested_object) nested_fields_to_apply.append({'field': key, 'value': nested_objects}) else: nested_fields_to_apply.append({'field': key, 'value': nested_model(**value)}) elif isinstance(nested_field_inspection.property, ColumnProperty): nested_fields_to_apply.append({'field': key, 'value': value}) else: raise InvalidType("Unrecognized nested field type: not a RelationshipProperty or ColumnProperty.") for nested_field in nested_fields_to_apply: setattr(obj, nested_field['field'], nested_field['value'])
def create_object(self, data, view_kwargs): """Create an object through sqlalchemy :param dict data: the data validated by marshmallow :param dict view_kwargs: kwargs from the resource view :return DeclarativeMeta: an object from sqlalchemy """ self.before_create_object(data, view_kwargs) relationship_fields = get_relationships(self.resource.schema, model_field=True) nested_fields = get_nested_fields(self.resource.schema, model_field=True) join_fields = relationship_fields + nested_fields obj = self.model(**{key: value for (key, value) in data.items() if key not in join_fields}) self.apply_relationships(data, obj) self.apply_nested_fields(data, obj) self.session.add(obj) try: self.session.commit() except JsonApiException as e: try: self.session.rollback() except Exception as e: print 'Rollback failed {}'.format(e) raise e self.after_create_object(obj, data, view_kwargs) return obj
def update_object(self, obj, data, view_kwargs): """Update an object through sqlalchemy :param DeclarativeMeta obj: an object from sqlalchemy :param dict data: the data validated by marshmallow :param dict view_kwargs: kwargs from the resource view :return boolean: True if object have changed else False """ if obj is None: url_field = getattr(self, 'url_field', 'id') filter_value = view_kwargs[url_field] raise ObjectNotFound('{}: {} not found'.format(self.model.__name__, filter_value), source={'parameter': url_field}) self.before_update_object(obj, data, view_kwargs) relationship_fields = get_relationships(self.resource.schema, model_field=True) nested_fields = get_nested_fields(self.resource.schema, model_field=True) join_fields = relationship_fields + nested_fields for key, value in data.items(): if hasattr(obj, key) and key not in join_fields: setattr(obj, key, value) self.apply_relationships(data, obj) self.apply_nested_fields(data, obj) try: self.session.commit() except JsonApiException as e: self.session.rollback() raise e self.after_update_object(obj, data, view_kwargs)
def related_schema(self): """Get the related schema of a related (relationship or nested) field :return Schema: the related schema """ related_field_name = self.name related_fields = get_relationships(self.schema) + get_nested_fields( self.schema) if related_field_name not in related_fields: raise InvalidFilters( "{} has no relationship or nested attribute {}".format( self.schema.__name__, related_field_name)) return self.schema._declared_fields[ related_field_name].schema.__class__
def related_model(self): """Get the related model of a related (relationship or nested) field :return DeclarativeMeta: the related model """ related_field_name = self.name related_fields = get_relationships(self.schema) + get_nested_fields( self.schema) if related_field_name not in related_fields: raise InvalidFilters( "{} has no relationship or nested attribute {}".format( self.schema.__name__, related_field_name)) return getattr(self.model, get_model_field( self.schema, related_field_name)).property.mapper.class_