PlaidFan
PlaidFan

Reputation: 797

SQLAlchemy context sensitive function for creating a composite value on insert and update

I'm trying to sort out how to add a context sensitive function (e.g. def get_user_full_name()) that will get triggered from the default and onupdate specifications on a column. I'm trying to set a composite field that combines the first and last names into a single full name value to avoid having to constantly concat the two fields in all queries.

I'm using the declarative approach. This is an example of a similar model:

class SomeMembers(Base):
    __tablename__ = 'some_members'
    __table_args__ = {'mysql_engine':'InnoDB'}

    SomeGroup = Column(Unicode(50), primary_key=True)
    UserID = Column(Unicode(50), primary_key=True)
    FullName = Column(Unicode(255), default=get_user_full_name, onupdate=get_user_full_name, index=True)
    FirstName = Column(Unicode(255), index=True)
    LastName = Column(Unicode(255), index=True)
    UserName = Column(Unicode(255))

This is the function that I wrote which reports in the stack trace that neither the FirstName or LastName keys are valid:

def get_user_full_name(context):
    return " ".join((context.compiled_parameters[0]['FirstName'],context.compiled_parameters[0]['LastName']))

It isn't clear to me how I can reference the two columns (FirstName and LastName) existing data to create a composite value to store for easy retrieval. For example, if I had a user named John Doe the get_user_full_name method should take "John" and "Doe" and return a full name value of "John Doe".

In the documentation it refers to context.current_parameters but that does not exist in my case. I suspect it is because we use the declarative approach. If it did work my get_user_full_name function would look like:

def get_user_full_name(context):
    return " ".join((context.current_parameters['FirstName'],context.current_parameters['LastName']))

I know this is probably trivial but I can't seem to crack the code on where this information is stored and how to access it dynamically.

A little insight would be much appreciated. I'm also open to a more elegant approach too.

Thanks in advance...

Cheers,

Paul

Upvotes: 4

Views: 1133

Answers (2)

julste
julste

Reputation: 351

Just in case somebody is looking for an answer.

You can use mapper-events

@event.listens_for(SomeMembers, 'before_insert')
def before_insert_function(mapper, connection, target):
        target.FullName = f"{target.FirstName} {target.LastName}"

Upvotes: 2

muhuk
muhuk

Reputation: 16085

I tried the following expression:

from sqlalchemy.sql.expression import column, literal, literal_column

Column('full_name', String, onupdate=literal_column("first_name") + literal(" ") + literal_column("last_name"))

It sort of works, but updates the full_name with the previous values of first_name and last_name. Using column yields the same result.

Would a composite column do the job?

Upvotes: 0

Related Questions