How to handle `default` column values before/after commit()

172 views
Skip to first unread message

jens.t...@gmail.com

unread,
May 6, 2019, 12:06:34 AM5/6/19
to sqlalchemy-alembic
Suppose the following code:

# We define a base for all DB objects, currently empty.
class _Base:
   
pass

Base = declarative_base(cls=_Base, metadata=MetaData(naming_convention=…))

# Then the objects.
class User(Base):
    __tablename__
= "users"

   
id = Column(UUID(), default=uuid.uuid4, primary_key=True)
   

For the majority of code this works well and the id is initialized whenever the object is committed. However, there are cases when I need to get a hold of a new object’s id and that happens before the commit. In such cases the id is not set yet, and I have extra code which sets the id manually.

That feels crummy to me.

Now I wonder if that’s poor implementation because a new object should always be committed before use, or if I should perhaps expand the _Base class, for example:

class _Base:

   
def __init__(self, *args, **kwargs):
       
super().__init__(args, kwargs)
        if hasargs(self, "id"):
           
self.id = uuid.uuid4()

That way, every object would have an id assigned and if the object is loaded from the db then that initial id would be overwritten. Not pretty either, but maybe less crummy than the current implementation.

What are your thoughts?

Much thanks!
Jens

jens.t...@gmail.com

unread,
May 6, 2019, 4:22:53 AM5/6/19
to sqlalchemy-alembic
Sorry, I meant flush in the above post and not commit!

Mike Bayer

unread,
May 6, 2019, 10:48:39 AM5/6/19
to sqlalchem...@googlegroups.com
yes but here is the most canonical approach:

import uuid

from sqlalchemy import Column
from sqlalchemy import event
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class HasUUID(object):
id = Column(UUID(), default=uuid.uuid4, primary_key=True)

@event.listens_for(HasUUID, "init", propagate=True)
def init(obj, arg, kw):
obj.id = uuid.uuid4()

class User(HasUUID, Base):
__tablename__ = 'user'


u1 = User()

print(u1.id)



Alternatively, you can write an event that scans for columns that
contain a Python level default and invokes them. I think I did this
for someone once but it's apparently not in the wiki, but in any case
doing this using class-level inheritance is IMO the cleanest way since
your User class takes on the role of HasUUID explicitly.






>
> Much thanks!
> Jens
>
> --
> You received this message because you are subscribed to the Google Groups "sqlalchemy-alembic" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy-alem...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages