def to_dict(self, refresh_on_empty=True): """ Return dict representation of model. Drill down to any relationships and serialize those too. Assume that the current object has been loaded (lazy/joined/etc) and don't try to expand anything, i.e., just serialize the currently loaded data. However, with one exception: refresh if current __dict__ is empty. """ d = {} descriptors = self.descriptors for field, value in six.iteritems(self.__dict__): if field not in descriptors: # skip non-descriptors continue if hasattr(value, "to_dict"): value = value.to_dict() elif is_sequence(value): value = [v.to_dict() if hasattr(v, "to_dict") else v for v in value] d[field] = value if not d and refresh_on_empty and self.session: # Model's __dict__ is empty but has a session associated with it. # Most likely the model was previously committed which resets the __dict__ state. # Refreshing from database will repopulate the model's __dict__. self.refresh() d = self.to_dict(refresh_on_empty=False) return d
def update(self, data_dict=None, strict=False, **kargs): '''Update model with arbitrary set of data.''' data = data_dict if isinstance(data_dict, dict) else kargs updatable_fields = self.strict_update_fields if strict else data.keys() relationships = self.relationships for field, value in iteritems(data): if hasattr(self, field) and field in updatable_fields: # consider v a dict if any of its elements are a dict if is_sequence(value): is_dict = any([isinstance(val, dict) for val in value]) else: is_dict = isinstance(value, dict) attr = getattr(self, field) if hasattr(attr, 'update') and is_dict and not isinstance(attr, dict): # nest calls to attr.update attr.update(value) else: if field in relationships and is_dict and not value: # If v is {} and we're trying to update a relationship attribute, # then we need to set to None to nullify relationship value. value = None setattr(self, field, value)
def update(self, data_dict=None, strict=False, **kargs): """ Update model with arbitrary set of data """ data = data_dict if isinstance(data_dict, dict) else kargs updatable_fields = self.strict_update_fields if strict else data.keys() relationships = self.relationships for k, v in six.iteritems(data): if hasattr(self, k) and k in updatable_fields: # consider v a dict if any of its elements are a dict v_is_dict = any([isinstance(_v, dict) for _v in v]) if is_sequence(v) else isinstance(v, dict) attr = getattr(self, k) if hasattr(attr, "update") and v_is_dict: # nest calls to attr.update if available and input is a data dict attr.update(v) else: if k in relationships and v_is_dict and not v: # typically, if v is {}, then we're usually updating a relationship attribute # where the relationship has an empty/null value in the database # (e.g. a frontend sends missing relationship attribute as {}) # but if we set a relationship attribute = {}, things blow up # so instead, convert {} to None which is valid for standard relationship attribute v = None setattr(self, k, v)
def to_dict(self): '''Return dict representation of model by filtering fields using `self.__to_dict__`. ''' data = {} data_fields = self.__to_dict__ for field in data_fields: value = getattr(self, field) # Nest calls to `to_dict`. Try to find method on base value, sequence values, or dict values if hasattr(value, 'to_dict'): value = value.to_dict() elif is_sequence(value): value = [v.to_dict() if hasattr(v, 'to_dict') else v for v in value] elif isinstance(value, dict): value = dict([(k, v.to_dict() if hasattr(v, 'to_dict') else v) for k, v in iteritems(value)]) data[field] = value return data