Search code examples
pythonsqlalchemymany-to-manyreturn-valuetraceback

AttributeError: 'InstrumentedList'


I am pretty new to using both SQLALCHEMY and the PYRAMID web framework. I am struggling with what might be a simple fix to some, but I haven't been able to figure it out. I have looked at some posts here on Stacks, but they don't quite answer my issue.

I have a many-to-many relationship in my database table. I am trying to return an object (categories) from the parent table assessment. I am trying at the moment to: return {'name': assessment.name, 'text': assessment.text, 'user': assessment.user_id, 'video':assessment.video_id, 'categories': assessment.categories.assessment_category_link} but this doesn't work --> 'categories': assessment.categories.assessment_category_link

I am able to return all the objects except categories. Below is the relevant error and code.

TRACEBACK:

 line 306, in get_assessment
    return {'name': assessment.name, 'text': assessment.text, 'user': assessment.user_id, 'video':assessment.video_id, 'categories': assessment.categories.assessment_category_link}
AttributeError: 'InstrumentedList' object has no attribute 'assessment_category_link'

SQLALCHEMY TABLE/RELATIONSHIP:

# MANY-to-MANY
association_table = Table('assessment_category_link', Base.metadata,
    Column('assessment_id', Integer, ForeignKey('assessments.assessment_id')),
    Column('category_id', Integer, ForeignKey('categories.category_id')))

class Assessment(Base):
    # column/entity code
    categories = relationship('Category', secondary='assessment_category_link', backref='assessments')

    def __init__(self, name, text, user, video, categories):
        # CODE 
        self.categories = categories

The GET() method, specifically the return value that is throwing the error:

@view_config(route_name='assessment', request_method='GET', renderer='json')
def get_assessment(request):
    with transaction.manager:
        assessment_id = int(request.matchdict['id'])
        assessment = api.retrieve_assessment(assessment_id)
        if not assessment:
            raise HTTPNotFound()
        return {'name': assessment.name, 'text': assessment.text, 'user': assessment.user_id, 'video':assessment.video_id, 'categories': assessment.categories.assessment_category_link}

Solution

  • I am not sure what you are trying to achieve since assessment.categories would return a list of Category objects that you need to iterate over. It is logical for such a list not to have an attribute named assessment_category_link (as the exception tells you), and it is not clear to me why you would want to access the association object anyway!

    The relationship with the secondary keyword argument is meant to hide this complexity away so that assessment.categories would transparently return the list that you're after.

    you can represent the categories list as you like, a suggestion for your case:

    {...., 'categories': ', '.join([str(i) for i in assessment.categories])}