It’s easy to use with sqlalchemy.ext.declarative
:
from sqlalchemy import Column, ForeignKey, Integer, Unicode
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_imageattach.entity import Image, image_attachment
Base = declarative_base()
class User(Base):
"""User model."""
id = Column(Integer, primary_key=True)
name = Column(Unicode, nullable=False)
picture = image_attachment('UserPicture')
__tablename__ = 'user'
class UserPicture(Base, Image):
"""User picture model."""
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
user = relationship('User')
__tablename__ = 'user_picture'
In the above example, we declare two entity classes. UserPicture
which
inherits Image
is an image entity,
and User
owns it. image_attachment()
function is a specialized relationship()
for image
entities. You can understand it as one-to-many relationship.
Every image class has object_type
string, which is used by the storage.
UserPicture
in the above example omits object_type
property,
but it can be overridden if needed. Its default value is the table name
(underscores will be replaced by hyphens).
When would you need to override object_type
? The most common case
is when you changed the table name. Identifiers like path names that
are internally used by the stoage won’t be automatically renamed even if
you change the table name in the relational database. So you need to
maintain the same object_type
value.
Every image instance has object_id
number, which is used by the storage. A pair of (object_type
, object_id
is an unique key for an image.
UserPicture
in the above example omits object_id
property, because it
provides the default value when the primary key is integer or UUID.
It has to be explicitly implemented when the primary key is not integer/UUID or
is composite key.
Changed in version 1.1.0: Since 1.1.0, object_id
has
a more default implementation for UUID
primary keys.
If a primary key is not composite and UUID
type,
object_id
for that doesn’t have
to be implemented.
For example, the most simple and easiest (although naive) way to implement
object_id
for the string primary
key is hashing it:
@property
def object_id(self):
return int(hashlib.sha1(self.id).hexdigest(), 16)
If the primary key is a pair, encode a pair into an integer:
@property
def object_id(self):
a = self.id_a
b = self.id_b
return (a + b) * (a + b) + a
If the primary key is composite of three or more columns, encode a tuple into a linked list of pairs first, and then encode the pair into an integer. It’s just a way to encode, and there are many other ways to do the same.