簡體   English   中英

使用多對多成員屬性查詢對象

[英]Querying objects using attribute of member of many-to-many

我有以下型號:

class Member(models.Model):
    ref = models.CharField(max_length=200)
    # some other stuff
    def __str__(self):
        return self.ref

class Feature(models.Model):
    feature_id = models.BigIntegerField(default=0)
    members = models.ManyToManyField(Member)
    # some other stuff

成員基本上只是指向功能的指針。 所以說我有功能:

  • feature_id = 2,成員= 1,2
  • feature_id = 4
  • feature_id = 3

那么成員將是:

  • id = 1,參考= 4
  • id = 2,參考= 3

我想從“確定的成員”列表中找到包含一個或多個成員的所有功能。 目前,我的查詢如下所示:

# ndtmp is a query set of member-less Features which Members can point to
sids = [str(i) for i in list(ndtmp.values('feature_id'))]
# now make a query set that contains all rels and ways with at least one member with an id in sids
okmems = Member.objects.filter(ref__in=sids)
relsways = Feature.geoobjects.filter(members__in=okmems)
# now combine with nodes
op = relsways | ndtmp

這非常慢,我什至不確定它是否有效。 我已經嘗試使用print語句進行調試,只是為了確保實際上已解析任何內容,並且得到以下信息:

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

...然后代碼只是掛了幾分鍾,最后我退出了。 我認為我只是使查詢過於復雜,但不確定如何最好地簡化它。 我是不是該:

  1. 遷移功能以使用CharField而不是BigIntegerField嗎? 我沒有真正的理由使用BigIntegerField,因為我在開始這個項目時一直在學習教程,所以我這樣做了。 我嘗試通過僅在models.py中進行更改來進行簡單的遷移,並且在PostgreSQL的列中使用“ Decimal :( the id)”格式獲得了“數值”值,但是可能有某種方法可以迫使它僅將ID推入字符串中。

  2. 使用我不知道的多對多字段的某些功能來更有效地檢查匹配項

  3. 計算每個要素的邊界框並將其存儲在另一列中,這樣我就不必在每次查詢數據庫時都進行此計算(因此,只需在遷移時計算一次固定的成本+每當我添加一個新功能或修改現有功能)?

或者是其他東西? 如果有幫助的話,這是針對我的正在進行的與OpenStreetMap相關的項目的服務器端腳本的,您可以在此處查看正在進行的工作。

編輯 -我認為獲取ndids一種更快的方法是這樣的:

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

這可以正常工作,產生一組非空的ID。 不幸的是,我對如何獲得okmems仍然不知所措。 我試過了:

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

但是它返回一個空的查詢集。 我可以通過以下測試確認參考點正確:

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

您應該看一下annotate

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

最終,使用一個表中的數字ID和另一個表中的文本類型ID來建立數據庫是錯誤的。 我對遷移還不是很熟悉,但是到某個時候,我將不得不深入研究那個世界,並弄清楚如何遷移我的數據庫以在兩個數據庫上使用數字。 現在,這有效:

# ndtmp is a query set of member-less Features which Members can point to
# get the unique ids from ndtmp as strings
strids = ndtmp.extra({'feature_id_str':"CAST( \
    feature_id AS VARCHAR)"}).order_by( \
    '-feature_id_str').values_list('feature_id_str',flat=True).distinct()
# find all members whose ref values can be found in stride
okmems = Member.objects.filter(ref__in=strids)
# find all features containing one or more members in the accepted members list
relsways = Feature.geoobjects.filter(members__in=okmems)
# combine that with my existing list of allowed member-less features
op = relsways | ndtmp
# prove that this set is not empty
op.count()
# takes about 10 seconds
>>> 8997148 # looks like it worked!

基本上,我正在創建一個feature_id (數字)查詢集,並將其轉換為文本類型( varchar )字段值的查詢集。 然后,我使用values_list使其僅包含這些字符串ID值,然后查找其ref ID在允許的功能列表中的所有成員。 現在,我知道允許哪些成員,因此我可以過濾掉該允許列表中包含一個或多個成員的所有功能。 最后,我將包含成員的允許功能查詢集合與ndtmp ,我的原始允許功能查詢集合不包含成員。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM