具有多对多字段的查询模型,以空列表作为输入

问题描述 投票:0回答:1

我有一个包含多对多字段的模型:

class Transaction(models.Model): 
    id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
    transaction_date = models.DateField(null=False, blank=False)
    transaction_category = models.ForeignKey(Category, on_delete=models.PROTECT, null=False, blank=False)
    customer_vendor = models.ForeignKey(CustomerVendor, on_delete=models.PROTECT, blank=False, null=False)
    account = models.ForeignKey(Account, on_delete=models.PROTECT, blank=False, null=False)
    reimbursable = models.BooleanField()
    tag = models.ManyToManyField(Tag, blank=True)
    amount = models.DecimalField(max_digits=12, decimal_places=2, null=False, blank=False)
    description = models.CharField(max_length=255, null=False, blank=False)

我有一个查询可以获取交易:

Transaction.objects.filter(transaction_category__master_category__category_type="Income", transaction_date__range=[start_date, end_date]).filter(exclude_reimbursable).order_by().annotate(month=ExtractMonth("transaction_date"), year=ExtractYear("transaction_date")).values("month", "year").annotate(month_year=Concat("month", V(" "), "year", output_field=CharField()), month_total=Sum("amount")).values("month_year", "month_total").order_by("year", "month")

我正在尝试将标签(多对多字段)添加到查询中。从网络应用程序中,我获取用户选择作为列表的所有标签。该列表也可以为空并且有 0 个标签。

我尝试在查询中使用

tag__in=tags
,但如果用户未选择任何标签,则它不起作用。如果用户没有选择任何标签,我们应该将其视为任何交易都可以返回,即使它没有选择任何标签。

我还尝试使用

Q(tag__in=tags) | Q(tag=None)
来获取具有任何标签或没有标签的交易,这应该执行我想要的操作,但它总是返回一个空查询集。

python django django-models
1个回答
0
投票

要解决这个问题,您需要单独处理没有选择标签的情况,并在存在标签时使用适当的查询逻辑。 当未选择任何标签时,您希望完全排除

tag__in=tags
过滤器。

解决方案:

  1. 提供标签后,请使用
    tag_in=tags
    过滤器。
  2. 当没有提供标签时,跳过标签过滤并包含所有交易。

这是代码。

from django.db.models import Q, Sum, CharField, Value as V
from django.db.models.functions import ExtractMonth, ExtractYear, Concat

# If tags is empty, we don't filter by tags.
if tags:
    transactions = Transaction.objects.filter(
        Q(transaction_category__master_category__category_type="Income"),
        Q(transaction_date__range=[start_date, end_date]),
        Q(tag__in=tags)
    )
else:
    transactions = Transaction.objects.filter(
        Q(transaction_category__master_category__category_type="Income"),
        Q(transaction_date__range=[start_date, end_date])
    )

# Exclude reimbursable transactions
if exclude_reimbursable:
    transactions = transactions.filter(reimbursable=False)

# Annotate the month and year, concatenate them, and sum the amount
transactions = transactions.annotate(
    month=ExtractMonth("transaction_date"),
    year=ExtractYear("transaction_date")
).values("month", "year").annotate(
    month_year=Concat("month", V(" "), "year", output_field=CharField()),
    month_total=Sum("amount")
).values("month_year", "month_total").order_by("year", "month")

希望这对你有一点帮助。

© www.soinside.com 2019 - 2024. All rights reserved.