⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vertical.py

📁 SQLAlchemy. 经典的Python ORM框架。学习必看。
💻 PY
字号:
"""this example illustrates a "vertical table".  an object is stored with individual attributes represented in distinct database rows.  This allows objects to be created with dynamically changingfields that are all persisted in a normalized fashion."""from sqlalchemy import *from sqlalchemy.orm import *from sqlalchemy.orm.collections import mapped_collectionimport datetimee = MetaData('sqlite://')e.bind.echo = TrueSession = scoped_session(sessionmaker(transactional=True))# this table represents Entity objects.  each Entity gets a row in this table,# with a primary key and a title.entities = Table('entities', e,     Column('entity_id', Integer, primary_key=True),    Column('title', String(100), nullable=False),    )# this table represents dynamic fields that can be associated# with values attached to an Entity.# a field has an ID, a name, and a datatype.  entity_fields = Table('entity_fields', e,    Column('field_id', Integer, primary_key=True),    Column('name', String(40), nullable=False),    Column('datatype', String(30), nullable=False))    # this table represents attributes that are attached to an # Entity object.  It combines a row from entity_fields with an actual value.# the value is stored in one of four columns, corresponding to the datatype# of the field value.entity_values = Table('entity_values', e,     Column('value_id', Integer, primary_key=True),    Column('field_id', Integer, ForeignKey('entity_fields.field_id'), nullable=False),    Column('entity_id', Integer, ForeignKey('entities.entity_id'), nullable=False),    Column('int_value', Integer),     Column('string_value', String(500)),    Column('binary_value', PickleType),    Column('datetime_value', DateTime))e.create_all()class Entity(object):    """represents an Entity.  The __getattr__ method is overridden to search the    object's _entities dictionary for the appropriate value, and the __setattribute__    method is overridden to set all non "_" attributes as EntityValues within the     _entities dictionary. """    def __getattr__(self, key):        """getattr proxies requests for attributes which dont 'exist' on the object        to the underying _entities dictionary."""        if key[0] == '_':            return super(Entity, self).__getattr__(key)        try:            return self._entities[key].value        except KeyError:            raise AttributeError(key)    def __setattr__(self, key, value):        """setattr proxies certain requests to set attributes as EntityValues within        the _entities dictionary.  This one is tricky as it has to allow underscore attributes,        as well as attributes managed by the Mapper, to be set by default mechanisms.  Since the         mapper uses property-like objects on the Entity class to manage attributes, we check        for the key as an attribute of the class and if present, default to normal __setattr__        mechanisms, else we use the special logic which creates EntityValue objects in the        _entities dictionary."""        if key[0] == "_" or hasattr(Entity, key):            object.__setattr__(self, key, value)            return        try:            ev = self._entities[key]            ev.value = value        except KeyError:            ev = EntityValue(key, value)            self._entities[key] = ev        class EntityField(object):    """this class represents a row in the entity_fields table."""    def __init__(self, name=None):        self.name = name        self.datatype = Noneclass EntityValue(object):    """the main job of EntityValue is to hold onto a value, corresponding the type of     the value to the underlying datatype of its EntityField."""    def __init__(self, key=None, value=None):        if key is not None:            self.field = Session.query(EntityField).filter(EntityField.name==key).first() or EntityField(key)            if self.field.datatype is None:                if isinstance(value, int):                    self.field.datatype = 'int'                elif isinstance(value, str):                    self.field.datatype = 'string'                elif isinstance(value, datetime.datetime):                    self.field.datatype = 'datetime'                else:                    self.field.datatype = 'binary'            setattr(self, self.field.datatype + "_value", value)    def _get_value(self):        return getattr(self, self.field.datatype + "_value")    def _set_value(self, value):        setattr(self, self.field.datatype + "_value", value)    name = property(lambda s: s.field.name)    value = property(_get_value, _set_value)# the mappers are a straightforward eager chain of # Entity--(1->many)->EntityValue-(many->1)->EntityField# notice that we are identifying each mapper to its connecting# relation by just the class itself.mapper(EntityField, entity_fields)mapper(    EntityValue, entity_values,    properties = {        'field' : relation(EntityField, lazy=False, cascade='all')    })mapper(Entity, entities, properties = {    '_entities' : relation(EntityValue, lazy=False, cascade='all', collection_class=mapped_collection(lambda entityvalue: entityvalue.field.name))})# create two entities.  the objects can be used about as regularly as# any object can.session = Session()entity = Entity()entity.title = 'this is the first entity'entity.name =  'this is the name'entity.price = 43entity.data = ('hello', 'there')entity2 = Entity()entity2.title = 'this is the second entity'entity2.name = 'this is another name'entity2.price = 50entity2.data = ('hoo', 'ha')# commit[session.save(x) for x in (entity, entity2)]session.flush()# we would like to illustate loading everything totally clean from # the database, so we clear out the sessionsession.clear()# select both objects and printentities = session.query(Entity).select()for entity in entities:    print entity.title, entity.name, entity.price, entity.data# now change some dataentities[0].price=90entities[0].title = 'another new title'entities[1].data = {'oof':5,'lala':8}entity3 = Entity()entity3.title = 'third entity'entity3.name = 'new name'entity3.price = '$1.95'entity3.data = 'some data'session.save(entity3)# commit changes.  the correct rows are updated, nothing else.session.flush()# lets see if that one came through.  clear the session, re-select# and printsession.clear()entities = session.query(Entity).select()for entity in entities:    print entity.title, entity.name, entity.price, entity.datafor entity in entities:    session.delete(entity)session.flush()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -