2013-08-08 5 views
4

У меня есть следующие отношения установить в модели:Определить, если свойство является backref в SQLAlchemy

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... 

Так как я теперь понимаю, что это работает, что свойство роли на объекте профиля будет содержать список ролевых классов (что он делает).

Что я хочу сделать, это сериализовать для каждого свойства класса модели в целом. Он отлично работает для верхнего профиля класса и определить, что есть список roles, что я должен рекурсия в:

# 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) 

Проблема заключается в том, что backref отношениях добавляет указатель на профиль. Затем один и тот же профиль сериализуется и повторяет роли снова и снова до stack overflow.

Есть ли способ определить, что свойство является backref, добавленным relationship?

Update

Может быть, я должен добавить, что он отлично работает в этом случае, если я удалить backref, так как я не нужно, но я хотел бы сохранить его.

Update

Как временное решение я добавил свойство класса к моему базовому классу:

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

    __backref__ = None 

и добавить его так:

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

    # Columns... 

и использовать его, как это в моем рекурсии:

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

Если есть лучший способ, пожалуйста, дайте мне знать, потому что это не выглядит оптимальным.

ответ

2

посмотреть на inspect

например

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

сделаю. Я вернусь ... Спасибо – Asken

+0

Будьте осторожны, чтобы вы не столкнулись с встроенным 'Python'' 'проверкой –

2

Вы можете создать в своем классе BaseModelMixin в __relationships__ как @property, который имеет список всех отношений имени, которые не являются как backref имя в модели.

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 

Как у вас есть два класса profile и role, так

>>> p = profile() 
>>> p.__relationships__ 
    # ['roles'] 

>>> r = role() 
>>> r.__relationships__ 
    # [] 
+0

Отличный ответ! sqlalchemy должно было облегчить идентификацию backrefs и отношений. –

1

Не уверен, что это лучшая практика, но этот код работает для меня. Он возвращает True, если атрибут является ссылкой, False, если используется обычный тип столбца.

def is_relation(orm_object, attr_name): 
    return hasattr(getattr(orm_object.__class__, attr_name).property, 'mapper') 
Смежные вопросы