简体   繁体   English

Django 中的查询集联合

[英]Queryset Union in Django

I'm trying to do a simple double entry accounting with Django.我正在尝试用 Django 做一个简单的复式记账。 Every transaction is currently one object with debit and credit accounts being foreign keys.当前,每笔交易都是一个对象,借方和贷方帐户是外键。 Now I'm trying to get all transaction objects out so that there's debit and credit object for every transaction and I can easily order and represent every account's transactions and totals in the template.现在我正在尝试取出所有交易对象,以便每笔交易都有借方和贷方对象,我可以轻松地在模板中订购和表示每个帐户的交易和总计。 So every transaction object needs to have debit object and credit object in the final outcome.所以每个交易对象在最终结果中都需要有借方对象和贷方对象。 I think in MySQL you could achieve this with something like:我认为在 MySQL 中,您可以通过以下方式实现:

SELECT date, description, amount, debit_account AS account, debit AS 1 FROM Transaction
UNION
SELECT date, description, amount, credit_account AS account, debit AS 0 FROM Transaction

What is the right way to do this with Python's objects in Django?使用 Django 中的 Python 对象执行此操作的正确方法是什么? Union seems to override the changes within the for loop I currently have and I end up with no distinction between debit and credit. Union 似乎覆盖了我目前拥有的 for 循环中的更改,我最终没有区分借方和贷方。

models.py

class Transaction(models.Model):
    date = models.DateField()
    description = models.CharField(max_length=150)
    debit_account = models.ForeignKey('ledger.Account', related_name='debit_account', blank=True, null=True, on_delete=models.CASCADE)
    credit_account = models.ForeignKey('ledger.Account', related_name='credit_account', blank=True, null=True, on_delete=models.CASCADE)
    amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    debit_in_ledger = models.BooleanField(default=False)


views.py

def ledger(request):

    transaction_list_debit = Transaction.objects.all()
    transaction_list_credit = Transaction.objects.all()

    for a in transaction_list_debit:
        a.debit_in_ledger = True

    transaction_list = transaction_list_debit.union(transaction_list_credit, all=True).order_by('debit_account', 'public_date')

    return render(request, 'pages/ledger.html', {'transaction_list' : transaction_list})

You can do this as follows:您可以按如下方式执行此操作:

from django.db.models import BooleanField, F, Value

q1 = Transaction.objects.annotate(
    account = F('debit_account')
    debit = Value(True, output_field=BooleanField())
)

q2 = Transaction.objects.annotate(
    account = F('credit_account')
    debit = Value(False, output_field=BooleanField())
)

qs = q1 | q2

where qs is thus our "final" queryset.因此, qs是我们的“最终”查询集。 This QuerySet will contain Transaction objects, and every Transaction object in the queryset will have two extra attributes: account and debit .这个QuerySet将包含Transaction对象,queryset 中的每个Transaction对象都有两个额外的属性: accountdebit Note that other attributes like debit_account , etc. will still exist.请注意,诸如debit_account等其他属性仍将存在。 Furthermore every real Transaction in the database will thus occur twice : once from q1 , and once from q2 .此外,数据库中的每个真实Transaction将因此发生两次:一次来自q1 ,一次来自q2

Furthermore the .account will contain the primary key of the related Account , so not a reference to the Account .此外, .account将包含相关Account键,因此不是对Account的引用。 You can then fetch the Account with Account.objects.get(pk=some_transaction.account) .然后,您可以使用Account.objects.get(pk=some_transaction.account)获取Account

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM