2

With SQLAlchemy I have a 1-1 relationship:

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)

class UserProfile(Base):
    __tablename__ = 'user_profiles'
    user_id = Column(Integer, ForeignKey(User.id), primary_key=True)
    user = relationship(User, 
                        backref=backref('profile', uselist=False), 
                        foreign_keys=did)

It's required that every User always has an associated UserProfile, even if created like this:

user = User()
session.add(user)
session.commit(user)

Is there a way to automatically create and associate a related entity?


Currently, I'm doing it this way:

@event.listens_for(User, 'init')
def on_user_init(target, args, kwargs):
    if not target.profile:
        target.profile = UserProfile()

However this sometimes results in

IntegrityError: (IntegrityError) duplicate key value violates unique constraint "user_profile_pkey" DETAIL: Key (user_id)=(1) already exists. 'INSERT INTO user_profiles ...

since UserProfile is assigned to a User which already exists.

ORM Event "before_insert" is not applicable since the docs clearly state it is not allowed to add new or modify current instances.

Any better way to achieve that?

1 Answer 1

1

The quick-and-easy way is to use "init" event, but filter out instances which have a primary key. Note that at the moment of instance initialization, it's empty, and kwargs argument contains the fields SqlAlchemy (or your code) is going to set on it:

@event.listens_for(User, 'init')
def on_user_init(target, args, kwargs):
    if not target.profile and 'id' not in kwargs:
        target.profile = UserProfile()

This still won't work when you save instances with id set manually (e.g. User(id=1)), but will cover most of other cases.

As for now, I don't see a better way.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.