[英]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 方法改進此功能的建議都將不勝感激。
如果我理解正確的話:
過濾對應於給定事件的 iocs:
iocs = IOCInfo.objects.filter(event=event)
獲取具有相同 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_type
和value
的任一條件來過濾事件,使用這個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.