簡體   English   中英

Django:使用 2 個字段過濾匹配對象

[英]Django: Filter matching objects using 2 fields

我有以下課程:


class Event(Model):
    ...

class IOCType(Model):
    name = CharField(max_length=50)

class IOCInfo(Model):
    event = ForeignKey(Event, on_delete=CASCADE, related_name="iocs"
    ioc_type = ForeignKey(IOCType, on_delete=CASCADE)
    value = CharField(max_lenght=50)

每個事件都有一個或多個與之關聯的 IOC,這些 IOC 存儲在 IOCInfo 表中。

這是創建一些事件后我的 IOCInfo 表的樣子:

ID 價值 事件編號 ioc_type_id
1個 一些價值1 事件ID1 4個
2個 一些價值2 事件ID1 8個
3個 一些價值3 事件ID1 8個
4個 一些價值4 事件ID1 1個
5個 一些價值3 事件id2 8個
6個 一些價值1 事件id2 1個
7 一些價值2 事件ID3 8個
8個 一些價值3 事件ID4 8個

我想要做的是獲取一個事件,將其 IOCInfo 與其他事件的 IOCInfo 進行比較,然后取回匹配的那些事件。

這是我到目前為止所做的並且它有效,但我擔心隨着數據庫的增長和應用程序有更多的用戶,這個查詢最終會成為瓶頸


def search_matches(event):
    matches = Event.objects.none() 
    for ioc in event.iocs.all():
        matches |= Event.objects.filter(
            iocs__ioc_type=ioc.ioc_type, iocs__value=ioc.value
        )
    return matches.exclude(event=event.id)

如果我將 eventid2 傳遞給上述函數,它將按預期返回 eventid1 和 eventid4。

任何使用任何 django 方法改進此功能的建議都將不勝感激。

如果我理解正確的話:

  1. 過濾對應於給定事件的 iocs:

     iocs = IOCInfo.objects.filter(event=event)
  2. 獲取具有相同 ioc 的事件(給定的除外)

     events = Event.objects.filter(iocs__in=iocs).exclude(pk=event.pk)

這將導致一個非常有效的查詢。

更新

要查看ioc的字段 - 用以下內容替換第 2 點:

events = Event.objects.filter(
    iocs__ioc__type__in=iocs.values_list('type', flat=True),
    iocs__ioc__value__in=iocs.values_list('value', flat=True)
).exclude(pk=event.pk)

讓我們看看我是否理解...

def search_matches(event):
    get_values = lambda data, key: [x[key] for x in data]
    data_to_filter = evetn.iocs.all().values('ioc_type', 'value').order_by('id')

    return Event.objects.filter(
        iocs__ioc_type__in=get_values(data_to_filter, ‘ioc_type’),
        iocs__value__in=get_values(data_to_filter, ‘value’)
    ).exclude(pk=event.id)

首先,您應該獲取ioc_type的值和指定 eventid 的 IOCInfo 的values

event_filters=IOCInfo.objects.filter(event=event).values("ioc_type","value")

那么你應該構造一個Q對象來根據最終滿足的ioc_typevalue的任一條件來過濾事件,使用這個Q對象來過濾你的事件

filtering_kwargs=Q()
for filter_ in event_filters:
    filtering_kwargs|=Q(**filter_)
matching_events=Event.objects.filter(**filtering_kwargs).exclude(id=event.id)

希望這能解決您的問題,因為無論您的數據有多大,db 都只會被查詢兩次

將所有內容組合在一個函數中變成

def search_matches(event):
    event_filters=IOCInfo.objects.filter(event=event).values("ioc_type","value")
    filtering_kwargs=Q()
    for filter_ in event_filters:
        filtering_kwargs|=Q(**filter_)
    matching_events=Event.objects.filter(**filtering_kwargs).exclude(id=event.id)
    return matching_events

暫無
暫無

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

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