Determine if backref property is in sqlalchemy

I have the following relationship set in the model:

role_profiles = Table('roleprofile', Base.metadata, Column('role_id', Integer, ForeignKey('role.id')), Column('profile_id', Integer, ForeignKey('profile.id')) ) class profile(Base): __tablename__ = 'profile' # Columns... roles = relationship('role', secondary=role_profiles, backref='profiles') class role(Base): __tablename__ = 'role' # Columns... 

So, now I understand that it works, since the role property in the profile object will contain a list of role classes (what it does).

I want to serialize for each property of the model class as a whole. It works fine for a top class profile, and I determine that there is a roles list that I have to register with:

 # I need a statement here to check if the field.value is a backref #if field.value is backref: # continue if isinstance(field.value, list): # Get the json for the list value = serialize.serialize_to_json(field.value) else: # Get the json for the value value = cls._serialize(field.value) 

The problem is that the backref relationship adds a pointer back to the profile. Then the same profile is serialized and repeats the roles over and over until stack overflow .

Is there a way to determine that the property is backref added by relationship ?

Update

Maybe I should add that it works fine in this case if I remove the backref since I don't need it, but I would like to keep it.

Update

As a temporary fix, I added a class property to the base class:

 class BaseModelMixin(object): """Base mixin for models using stamped data""" __backref__ = None 

and add it like this:

 class role(Base): __tablename__ = 'role' __backref__ = ('profiles', ) # Columns... 

and use it in my recursion:

 if self.__backref__ and property_name in self.__backref__: continue 

If there is a better way, let me know because it does not look optimal.

+4
source share
3 answers

look inspect

eg.

 from sqlalchemy import inspect mapper = inspect(MyModelClass) # dir(mapper) # mapper.relationships.keys() 
+2
source

You can create __relationships__ in your BaseModelMixin class as @property , which has a list of all relationship names that are not backref in the model.

 class BaseModelMixin(object): """Base mixin for models using stamped data""" @property def __relationships__(self): """ Return a list of relationships name which are not as a backref name in model """ back_ref_relationships = list() items = self.__mapper__.relationships.items() for (key, value) in items: if isinstance(value.backref, tuple): back_ref_relationships.append(key) return back_ref_relationships 

Since you have two classes profile and role , therefore

 >>> p = profile() >>> p.__relationships__ # ['roles'] >>> r = role() >>> r.__relationships__ # [] 
+2
source

Not sure if this is best practice, but this code works for me. It returns True if the attribute is a link, False if a regular column type is used.

 def is_relation(orm_object, attr_name): return hasattr(getattr(orm_object.__class__, attr_name).property, 'mapper') 
+1
source

Source: https://habr.com/ru/post/1495957/


All Articles