def __getattr__(self, key): if is_instrumented(self, key): return get_attribute(self, key) else: try: return self._goofy_dict[key] except KeyError: raise AttributeError(key)
def update_by_ma(self, schema, instance, commit=True): """根据marshmallow以及SQLa实例更新 :param schema: Schema Schema类或实例 :param instance: object Model对象 :param commit: bool 是否commit 此方法用以更新Sqla实例的字段,基于一个marshmallow类或实例, 根据marshmallow类的load字段加载。由于需要一个临时变量的 instance,对于需要同时处理复杂relationship的子关系需要增 加指定active_history=True来跟踪变化以维持正确的加载。 形如: >>> class Remote(Model): id = Column(Integer(), primary_key=True) name = Column(String(80)) >>> class Local(Model): id = Column(Integer(), primary_key=True) remote_id = Column(Integer()) remote = relationship("Remote", active_history=True, backref=backref('local', active_history=True) ) 在这里需要修改Remote中name以及关系时。 """ from sqlalchemy.orm.attributes import ( get_attribute, del_attribute, set_attribute, ) from marshmallow import Schema if not isinstance(schema, Schema): schema = schema() db.session.add(instance) loadable_fields = [ k for k, v in schema.fields.items() if not v.dump_only ] with db.session.no_autoflush: for field in loadable_fields: set_attribute(self, field, get_attribute(instance, field)) del_attribute(instance, field) db.session.expunge(instance) self.save(commit)
def before_insert(self, mapper, connection, instance): fields = [get_attribute(instance, f) for f in self.generate_from] table = mapper.columns[self.slugfield].table column = table.c[self.slugfield] assert isinstance(column.type, (db.Unicode, db.String)) max_length = column.type.length # filter out fields with no value as we cannot join them they are # not relevant for slug generation. fields = ifilter(None, fields) slug = self.separator.join(imap(gen_ascii_slug, fields)) # strip the string if max_length is applied slug = slug[:max_length-4] if max_length is not None else slug set_attribute(instance, self.slugfield, find_next_increment(getattr(instance.__class__, self.slugfield), slug, max_length)) return orm.EXT_CONTINUE
def before_insert(self, mapper, connection, instance): fields = [get_attribute(instance, f) for f in self.generate_from] table = mapper.columns[self.slugfield].table column = table.c[self.slugfield] assert isinstance(column.type, (db.Unicode, db.String)) max_length = column.type.length # filter out fields with no value as we cannot join them they are # not relevant for slug generation. fields = ifilter(None, fields) slug = self.separator.join(imap(gen_ascii_slug, fields)) # strip the string if max_length is applied slug = slug[:max_length - 4] if max_length is not None else slug set_attribute( instance, self.slugfield, find_next_increment(getattr(instance.__class__, self.slugfield), slug, max_length)) return orm.EXT_CONTINUE
def create_version(obj, session, before_flush=False, deleted=False, new=False): obj_mapper = object_mapper(obj) history_mapper = obj.__history_mapper__ history_cls = history_mapper.class_ obj_state = attributes.instance_state(obj) attr = {} obj_changed = False for om, hm in zip(obj_mapper.iterate_to_root(), history_mapper.iterate_to_root()): if hm.single: continue for hist_col in hm.local_table.c: if hist_col.key in ["version", "created"]: continue obj_col = om.local_table.c[hist_col.key] # get the value of the # attribute based on the MapperProperty related to the # mapped column. this will allow usage of MapperProperties # that have a different keyname than that of the mapped column. try: prop = obj_mapper.get_property_by_column(obj_col) except UnmappedColumnError: # in the case of single table inheritance, there may be # columns on the mapped table intended for the subclass only. # the "unmapped" status of the subclass column on the # base class is a feature of the declarative module as of sqla 0.5.2. continue # expired object attributes and also deferred cols might not be in the # dict. force it to load no matter what by using getattr(). if prop.key not in obj_state.dict: getattr(obj, prop.key) a, u, d = attributes.get_history(obj, prop.key) c = attributes.get_attribute(obj, prop.key) if d: attr[hist_col.key] = c obj_changed = True elif u: attr[hist_col.key] = c else: # if the attribute had no value. attr[hist_col.key] = c obj_changed = True if not obj_changed: # not changed, but we have relationships. OK # check those too for prop in obj_mapper.iterate_properties: if isinstance(prop, RelationshipProperty) and attributes.get_history(obj, prop.key).has_changes(): obj_changed = True break if not obj_changed and not deleted and not new: return if before_flush: obj.version += 1 return attr["version"] = obj.version hist = history_cls() for key, value in attr.iteritems(): setattr(hist, key, value) if deleted: action = "delete" elif new: action = "create" else: action = "update" from humusha.apps.words.models import Change change = Change( row_id=obj.id, word_id=obj.dependant_word_id, version=obj.version, model=obj.__class__.__name__, action=action ) session.add(change) # if new: # hist.version = 0 session.add(hist) obj.version += 1 session.add(obj)
def _setattr_from_instance(self, fields: List[str], instance: db.Model): with db.session.no_autoflush: for field in fields: set_attribute(self, field, get_attribute(instance, field)) del_attribute(instance, field)
def _setattr_from_instance(self, fields: List[str], instance: _M) -> None: with self.session().no_autoflush: for field in fields: set_attribute(self.instance(), field, get_attribute(instance, field)) del_attribute(instance, field)