按相关元素的可选列表过滤元素
Filter elements by optional lists of related elements
我有一种感觉,我把事情变得比他们需要的更复杂了——这不可能是一种罕见的情况。在我看来,这应该是可能的 - 或者也许我做的事情从根本上是错误的。
手头的问题是这样的:我已经声明了一个数据库元素,Element
,它由大约 10 个与其他元素的多对多关系组成,其中之一是 Tag
.
我想让我的应用程序的用户能够通过所有这些关系过滤 Element
,其中一些关系或其中的 none。假设用户只想查看与某个 Tag
.
相关的 Element
s
为了让事情变得更加困难,执行这个 objective 的函数是从 graphql API 调用的,这意味着它将接收 ID 而不是 ORM 对象。
我正在尝试在我的 Python Flask 项目中构建解析器,使用 SQLAlchemy,它将提供如下接口:
# graphql request
query getElements {
getElements(tags:[2, 3] people:[8, 13]) {
id
}
}
# graphql response
{
"data": {
"getElements": [
{
"id": "2"
},
{
"id": "3"
},
{
"id": "8"
}
]
}
}
我想象解析器看起来像这个简化的伪代码,但我终究无法弄清楚如何实现它:
def get_elements(tags=None, people=None):
args = {'tags' : tags, 'people' : people}
if any(args):
data_elements = DataElement.query.filter_by(this in args) # this is the tricky bit - for each of DataElements related elements, I want to check if its ID is given in the corresponding argument
else:
data_elements = DataElement.query.all()
return data_elements
这是应要求对简化数据库模型的一瞥。 DataElement 拥有很多这样的关系,并且它完美地工作:
class DataElement(db.Model):
__tablename__ = 'DataElement'
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=DataElementTag, back_populates='data_elements')
class Tag(db.Model):
__tablename__ = 'Tag'
id = db.Column(db.Integer, primary_key=True)
data_elements = db.relationship('DataElement', secondary=DataElementTag, back_populates='tags')
DataElementTag = db.Table('DataElementTag',
db.Column('id', db.Integer, primary_key=True),
db.Column('data_element_id', db.Integer, db.ForeignKey('DataElement.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('Tag.id'))
)
拜托,ORM 奇才和 python 怪胎,我向你求助!
我以一种相当笨拙的方式解决了它。我想一定有更优雅的方法来解决这个问题,我仍在等待更好的答案。
我最终遍历了所有给定的参数并使用 eval()
(不是用户输入,不用担心)来获取相应的数据库模型。从那里,我能够获取具有多对多关系的 DataElement
对象。我的最终解决方案如下所示:
args = {
'status' : status,
'person' : people,
'tag' : tags,
'event' : events,
'location' : locations,
'group' : groups,
'year' : year
} # dictionary for args for easier data handling
if any(args.values()):
final = [] # will contain elements matching criteria
for key, value in args.items():
if value:
model = eval(key.capitalize()) # get ORM model from dictionary key name (eval used on hardcoded string, hence safe)
for id in value:
filter_element = model.query.filter_by(id=id).one_or_none() # get the element in question from db
if filter_element:
elements = filter_element.data_elements # get data_elements linked to element in question
for element in elements:
if not element in final: # to avoid duplicates
final.append(element)
return final
我有一种感觉,我把事情变得比他们需要的更复杂了——这不可能是一种罕见的情况。在我看来,这应该是可能的 - 或者也许我做的事情从根本上是错误的。
手头的问题是这样的:我已经声明了一个数据库元素,Element
,它由大约 10 个与其他元素的多对多关系组成,其中之一是 Tag
.
我想让我的应用程序的用户能够通过所有这些关系过滤 Element
,其中一些关系或其中的 none。假设用户只想查看与某个 Tag
.
Element
s
为了让事情变得更加困难,执行这个 objective 的函数是从 graphql API 调用的,这意味着它将接收 ID 而不是 ORM 对象。
我正在尝试在我的 Python Flask 项目中构建解析器,使用 SQLAlchemy,它将提供如下接口:
# graphql request
query getElements {
getElements(tags:[2, 3] people:[8, 13]) {
id
}
}
# graphql response
{
"data": {
"getElements": [
{
"id": "2"
},
{
"id": "3"
},
{
"id": "8"
}
]
}
}
我想象解析器看起来像这个简化的伪代码,但我终究无法弄清楚如何实现它:
def get_elements(tags=None, people=None):
args = {'tags' : tags, 'people' : people}
if any(args):
data_elements = DataElement.query.filter_by(this in args) # this is the tricky bit - for each of DataElements related elements, I want to check if its ID is given in the corresponding argument
else:
data_elements = DataElement.query.all()
return data_elements
这是应要求对简化数据库模型的一瞥。 DataElement 拥有很多这样的关系,并且它完美地工作:
class DataElement(db.Model):
__tablename__ = 'DataElement'
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=DataElementTag, back_populates='data_elements')
class Tag(db.Model):
__tablename__ = 'Tag'
id = db.Column(db.Integer, primary_key=True)
data_elements = db.relationship('DataElement', secondary=DataElementTag, back_populates='tags')
DataElementTag = db.Table('DataElementTag',
db.Column('id', db.Integer, primary_key=True),
db.Column('data_element_id', db.Integer, db.ForeignKey('DataElement.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('Tag.id'))
)
拜托,ORM 奇才和 python 怪胎,我向你求助!
我以一种相当笨拙的方式解决了它。我想一定有更优雅的方法来解决这个问题,我仍在等待更好的答案。
我最终遍历了所有给定的参数并使用 eval()
(不是用户输入,不用担心)来获取相应的数据库模型。从那里,我能够获取具有多对多关系的 DataElement
对象。我的最终解决方案如下所示:
args = {
'status' : status,
'person' : people,
'tag' : tags,
'event' : events,
'location' : locations,
'group' : groups,
'year' : year
} # dictionary for args for easier data handling
if any(args.values()):
final = [] # will contain elements matching criteria
for key, value in args.items():
if value:
model = eval(key.capitalize()) # get ORM model from dictionary key name (eval used on hardcoded string, hence safe)
for id in value:
filter_element = model.query.filter_by(id=id).one_or_none() # get the element in question from db
if filter_element:
elements = filter_element.data_elements # get data_elements linked to element in question
for element in elements:
if not element in final: # to avoid duplicates
final.append(element)
return final