我有一个包含多对多字段的模型:
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)
来获取具有任何标签或没有标签的交易,这应该执行我想要的操作,但它总是返回一个空查询集。
要解决这个问题,您需要单独处理没有选择标签的情况,并在存在标签时使用适当的查询逻辑。 当未选择任何标签时,您希望完全排除
tag__in=tags
过滤器。
tag_in=tags
过滤器。这是代码。
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")
希望这对你有一点帮助。