【发布时间】:2022-01-27 20:52:01
【问题描述】:
我想创建一个引用三个相关模型的查询集,并允许我进行过滤。 SQL 可能如下所示:
SELECT th.id, th.customer, ft.filename, fva.path
FROM TransactionHistory th
LEFT JOIN FileTrack ft
ON th.InboundFileTrackID = ft.id
LEFT JOIN FileViewArchive fva
ON fva.FileTrackId = ft.id
WHERE th.customer = 'ACME, Inc.'
-- AND ft.filename like '%storage%' --currently don't need to do this, but seeing placeholder logic would be nice
我在 Django 中有三个模型,如下所示。这有点棘手,因为 TransactionHistory 模型对同一个模型 (FileTrack) 有两个外键。 FileViewArchive 有一个 FileTrack 的外键。
class FileTrack(models.Model):
id = models.BigIntegerField(db_column="id", primary_key=True)
filename = models.CharField(db_column="filename", max_length=128)
class Meta:
managed = False
db_table = "FileTrack"
class TransactionHistory(models.Model):
id = models.BigIntegerField(db_column="id", primary_key=True)
customer = models.CharField(db_column="Customer", max_length=128)
inbound_file_track = models.ForeignKey(
FileTrack,
db_column="InboundFileTrackId",
related_name="inbound_file_track_id",
on_delete=models.DO_NOTHING,
null=True,
)
outbound_file_track = models.ForeignKey(
FileTrack,
db_column="OutboundFileTrackId",
related_name="outbound_file_track_id",
on_delete=models.DO_NOTHING,
null=True,
)
class Meta:
managed = False
db_table = "TransactionHistory"
class FileViewArchive(models.Model):
id = models.BigIntegerField(db_column="id", primary_key=True)
file_track = models.ForeignKey(
FileTrack,
db_column="FileTrackId",
related_name="file_track_id",
on_delete=models.DO_NOTHING,
null=True,
)
path = models.CharField(db_column="Path", max_length=256)
class Meta:
managed = False
db_table = "FileViewArchive"
我尝试过的一件事:
qs1 = TransactionHistory.objects.select_related('inbound_file_track').filter(customer='ACME, Inc.')
qs2 = FileViewArchive.objects.select_related('file_track').all()
qs = qs1 & qs2 # doesn't work b/c they are different base models
而this idea 使用链也不起作用,因为它发送两个单独的查询,我不完全确定它是否/如何合并它们。我正在寻找一个查询以提高性能。它还返回一个可迭代的,所以我不确定我是否可以在我的视图中使用它(Django Rest Framework)。最后下面的 x 返回一个 TransactionHistory 对象,所以我什至无法访问其他两个模型的字段。
from itertools import chain
c = chain(qs1 | qs2) # great that his this lazy and doesn't evaluate until used!
type(c) # this returns <class 'itertools.chain'> and it doesn't consolidate
x = list(c)[0] # runs two separate queries
type(x) # a TransactionHistory object -> so no access to the Filetrack or FileViewArchive fields
有什么想法可以将三个模型连接在一起吗?像这样?:
qs = TransactionHistory.objects.select_related('inbound_file_track').select_related('file_track').filter(customer='ACME, Inc.', file_track__filename__contains='storage')
更多信息:这是视图的一部分,如下所示。它返回一个查询集,用作 Django Rest Framework 视图的一部分。
class Transaction(generics.ListAPIView):
serializer_class = TransactionSerializer
def filter_queryset(self, queryset):
query_params = self.request.query_params.copy()
company = query_params.pop("company", [])[0]
filename = query_params.pop("filename", [])[0]
# need code here that generate filtered queryset for filename and company
# qs = TransactionHistory.objects.select_related('inbound_file_track').select_related('file_track').filter(customer='ACME, Inc.', file_track__filename__contains='storage')
return qs.order_by("id")
【问题讨论】:
-
你能分享一下你期望的输出吗?
-
我想返回一个过滤后的视图集。我会补充问题,谢谢!
-
根据您共享的 sql 查询,您正在根据
inbound_file_track文件名进行过滤。所以这样的事情应该可以工作:TransactionHistory.objects.select_related('inbound_file_track').prefetch_related('inbound_file_track__file_track_id').filter(customer='ACME, Inc.', inbound_file_track___filename__contains='storage') -
@BrianDestura,是的,这行得通,谢谢!你想创建一个答案以便我接受吗?
-
不客气!我已将此作为答案发布
标签: django django-models django-views django-queryset