DRYing up model relationships with custom properties

27 views
Skip to first unread message

Tony Cosentini

unread,
May 3, 2023, 4:18:04 AM5/3/23
to sqlalchemy
Hi,

I have a pattern in some models where there is a private (as in prefixed with __) relationship and then a property to handle some things that need to happen when the relationship is fetched or written to.

Currently it's implemented like this:
class ModelClass(Base):
  __field_for_relationship = relationship('OtherModel')
  @property
  def field_for_relationship(self):
    # Some custom logic
    return self.__field_for_relationship
 
  @field_for_relationship.setter
  def field_for_relationship(self, value: OtherModel):
    # Some custom logic.
    self.__field_for_relationship = value

This works, but I'd like to DRY this up into some kind of nice one-liner if possible because I'm using this pattern on a handful of relationships. However, it seems like the relationship field itself needs to be on the model because of some magic that happens under the hood.

Any ideas on if it's possible to combine this into some kind of reusable utility to DRY it up?

I'm not sure how important it is, but I'm still on 1.4.x, haven't made the jump to 2.x yet.

Thanks!
Tony

Mike Bayer

unread,
May 3, 2023, 9:27:57 AM5/3/23
to noreply-spamdigest via sqlalchemy
I'd be a little concerned about the double-underscore as it modifies the way Python getattr() works for those names, and I dont know that we have tests for that specific part of it, but besides that, you can always add new relationships or other mapped attributes to classes in one of two ways:

1. when using declarative Base, you can assign it:  ModelClass._field_for_rel = relationship()
2. you can set it in the mapper:  ModelClass.__mapper__.add_property("_field_for_rel", relationship())


so you could make use of that code within some kind of function that is applied to the class with a certain name.

if you are looking to do it fully inline within the class, you might need to use event hooks that receive the class and mapper so that you can apply things after the fact, a good event for this would be "instrument_class": https://docs.sqlalchemy.org/en/20/orm/events.html#sqlalchemy.orm.MapperEvents.instrument_class
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
 
 
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.

Tony Cosentini

unread,
May 4, 2023, 1:55:08 AM5/4/23
to sqlalchemy
Just to follow up on what I ended up doing - I went with approach 1 and created a function that would add it. I also switched from __ to _ to avoid any surprises.

Thanks again for the suggestions!
Reply all
Reply to author
Forward
0 new messages