Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 (e.g., using before-insert triggers?)

like image 343
saabeilin Avatar asked May 13 '13 13:05

saabeilin


People also ask

What is Write Once Read Many in computer?

What is WORM (write once, read many)? In computer media, write once, read many, or WORM, is a data storage technology that allows data to be written to a storage medium a single time and prevents the data from being erased or modified.

How does Write Once Read Many work?

Write once read many (WORM) describes a data storage device in which information, once written, cannot be modified. This write protection affords the assurance that the data cannot be tampered with once it is written to the device.

What is WORM CDR?

In computer memory: Optical discs. CD-R (CD-recordable), or WORM (write-once read-many), is a variation of CD-ROM on which a user may record information but not subsequently change it. CD-RW (CD-rewritable) disks can be re-recorded.

What is WORM disk explain with example?

The simple explanation is that it's immutable storage. You can write data to the storage device or media precisely one time. After that, no one can legitimately change the data in any way. A simple version of WORM storage is a CD-R disc. You can write data to the blank disc, but then it's stuck that way forever.


1 Answers

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.

like image 153
zzzeek Avatar answered Sep 21 '22 04:09

zzzeek