Use AssociationProxyInstance instead of AssociationProxy

Since [1], an AssociationProxy proxy instance is an
AssociationProxyInstance derivative object.

In order to import versions SQLAlchemy>=1.3.x, we need to handle
both implementations.

[1]6446e0dfd3

Change-Id: Ieba1a0315b4588841210078fa13f99f3d5275426
Closes-Bug: #1824178
This commit is contained in:
Rodolfo Alonso Hernandez 2019-04-10 15:34:25 +00:00
parent 3fd0a3c4d7
commit a0b39121cd
3 changed files with 20 additions and 8 deletions

View File

@ -17,7 +17,6 @@ NOTE: This module is a temporary shim until networking projects move to
"""
from oslo_db.sqlalchemy import utils as sa_utils
from sqlalchemy import sql, or_, and_
from sqlalchemy.ext import associationproxy
from neutron_lib._i18n import _
from neutron_lib.api import attributes
@ -26,6 +25,7 @@ from neutron_lib import exceptions as n_exc
from neutron_lib.objects import utils as obj_utils
from neutron_lib.utils import helpers
# Classes implementing extensions will register hooks into this dictionary
# for "augmenting" the "core way" of building a query for retrieving objects
# from a model class. Hooks are registered by invoking register_hook().
@ -180,7 +180,10 @@ def apply_filters(query, model, filters, context=None):
if not value:
query = query.filter(sql.false())
return query
if isinstance(column, associationproxy.AssociationProxy):
if not hasattr(column, 'in_'):
# NOTE(ralonsoh): since SQLAlchemy==1.3.0, a column is an
# AssociationProxyInstance and inherits in_() method from
# ColumnOperators.
# association proxies don't support in_ so we have to
# do multiple equals matches
query = query.filter(

View File

@ -14,7 +14,8 @@ import six
from oslo_db import exception as db_exc
from oslo_utils import excutils
from sqlalchemy.ext import associationproxy
import sqlalchemy
from sqlalchemy.ext.associationproxy import ASSOCIATION_PROXY
from sqlalchemy.orm import exc
from sqlalchemy.orm import properties
@ -148,11 +149,12 @@ def filter_non_model_columns(data, model):
:returns: A new dict who's keys are columns in model or are association
proxies of the model.
"""
columns = [c.name for c in model.__table__.columns]
return dict((k, v) for (k, v) in
data.items() if k in columns or
isinstance(getattr(model, k, None),
associationproxy.AssociationProxy))
mapper = sqlalchemy.inspect(model)
columns = set(c.name for c in mapper.columns)
columns.update(d.value_attr for d in mapper.all_orm_descriptors
if d.extension_type is ASSOCIATION_PROXY)
return dict((k, v) for (k, v)
in data.items() if k in columns)
def model_query_scope_is_project(context, model):

View File

@ -0,0 +1,7 @@
---
other:
- |
Since `commit <https://github.com/sqlalchemy/sqlalchemy/commit/6446e0dfd3e3bb60754bad81c4d52345733d94e3>`_,
an AssociationProxy proxy instance is an AssociationProxyInstance
derivative object. In order to import versions SQLAlchemy>=1.3.x, we need
to handle both implementations.