简体   繁体   中英

Write-once read-only field

We need to implement a write-once (on object create) read-only field with SQLAlchemy/Elixir.

A quick-and-dirty solution:

class User(Entity):
    # some fields ...    
    _created    = Field(DateTime, default=datetime.utcnow)
    @property
    def created(self):
        return self._created

Is there a better approach (eg, using before-insert triggers?)

Probably a lot of ways but one is to use a @validates :

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)

    readonly1 = Column(String)
    readonly2 = Column(String)


    @validates('readonly1', 'readonly2')
    def _write_once(self, key, value):
        existing = getattr(self, key)
        if existing is not None:
            raise ValueError("Field '%s' is write-once" % key)
        return value


a1 = A()
a1.readonly1 = 'foo'
assert a1.readonly1 == 'foo'

try:
    a1.readonly1 = 'bar'
    assert False
except ValueError, e:
    print e

e = create_engine("sqlite://")
Base.metadata.create_all(e)
s = Session(e)
s.add(A(readonly1='foo', readonly2='bar'))
s.commit()

a2 = s.query(A).first()

try:
    a2.readonly2 = 'bar2'
    assert False
except ValueError, e:
    print e

@validates is just shorthand for using attribute events which you could use that to build out other ways of setting it up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM