使用多对多成员的属性查询对象

3 浏览
0 Comments

使用多对多成员的属性查询对象

我有以下模型:\n

class Member(models.Model):
    ref = models.CharField(max_length=200)
    # 其他一些内容
    def __str__(self):
        return self.ref
class Feature(models.Model):
    feature_id = models.BigIntegerField(default=0)
    members = models.ManyToManyField(Member)
    # 其他一些内容

\nMember基本上只是指向Feature的指针。假设我有以下Features:\n- feature_id = 2, members = 1, 2\n- feature_id = 4\n- feature_id = 3\n那么成员将是:\n- id = 1, ref = 4\n- id = 2, ref = 3\n我想找到包含一个或多个\"ok members\"列表中成员的所有Features。当前我的查询如下:\n

# ndtmp是一个没有成员指向的Features的查询集合
sids = [str(i) for i in list(ndtmp.values('feature_id'))]
# 现在创建一个查询集合,其中包含至少一个具有在sids中具有id的成员的所有rels和ways
okmems = Member.objects.filter(ref__in=sids)
relsways = Feature.geoobjects.filter(members__in=okmems)
# 现在与nodes结合
op = relsways | ndtmp

\n这个查询非常慢,我甚至不确定它是否有效。我尝试使用打印语句进行调试,只是为了确保是否有被解析的内容,我得到以下结果:\n

print(ndtmp.count())
>>> 12747
print(len(sids))
>>> 12747
print(okmems.count())

\n...然后代码会在几分钟后卡住,最终我放弃了。我认为我只是把查询复杂化了,但我不确定如何最好地简化它。我应该:\n1. 将Feature迁移到使用CharField而不是BigIntegerField?我没有真正的理由使用BigIntegerField,只是因为在开始这个项目时我在跟随教程。我尝试通过在models.py中进行简单的迁移,但在PostgreSQL中得到了一个\'numeric\'值,格式为\'Decimal:(id)\',但可能有某种方法可以强制将其转换为字符串。\n2. 使用我不知道的Many-To-Many Fields的某些特性来更有效地检查匹配项\n3. 计算每个Feature的边界框并将其存储在另一列中,以便在每次查询数据库时不必进行此计算(因此只有在迁移时计算的固定成本+每次添加新Feature或修改现有Feature时计算的成本)?\n还是其他什么方式?如果有帮助的话,这是我正在进行的一个与OpenStreetMap相关的项目的服务器端脚本,您可以在进展中查看这里。\n编辑 - 我认为获取ndids的更快方法是这样的:\n

ndids = ndtmp.values_list('feature_id', flat=True)

\n这个方法有效,得到了一个非空的id集合。\n不幸的是,我仍然不知道如何得到okmems。我尝试了:\n

okmems = Member.objects.filter(ref__in=str(ndids))

\n但它返回一个空的查询集。我可以通过以下测试确认引用点是正确的:\n

Member.objects.values('ref')[:1]
>>> [{'ref': '2286047272'}]
Feature.objects.filter(feature_id='2286047272').values('feature_id')[:1]
>>> [{'feature_id': '2286047272'}]

0
0 Comments

问题的出现原因是数据库中一个表使用了数字id,另一个表使用了文本类型id。作者意识到这个问题后,通过将查询集中的数字id转换为文本类型id来解决这个问题。首先,作者使用extra方法将数字id转换为文本类型id,并使用values_list方法将查询集中的结果限制为只包含这些字符串id值。然后,作者找到所有ref值在允许的特征列表中的成员。接下来,作者找到所有包含一个或多个在允许的成员列表中的成员的特征。最后,作者将这个包含成员的允许特征的查询集与原始查询集ndtmp合并。通过这种方法,作者成功地解决了该问题。

原文链接:this answer and this question, not the answers to it though haha

0
0 Comments

问题的出现原因是:在查询具有多对多关系的成员属性时,使用了错误的查询语句,导致结果不正确。

解决方法是:使用Django框架的annotate函数进行查询。首先,使用annotate函数对Member对象进行注解,计算每个Member对象关联的Feature数量。然后,使用filter函数过滤出Feature数量大于等于1的Member对象。最后,使用filter函数根据过滤出的Member对象查询其关联的Feature对象。

具体代码如下:

okmems = Member.objects.annotate(
    feat_count=models.Count('feature')).filter(feat_count__gte=1)
relsways = Feature.geoobjects.filter(members__in=okmems)

以上是问题的出现原因和解决方法的整理。

0