【问题标题】:Django query for total balance from different currency walletsDjango查询不同货币钱包的总余额
【发布时间】:2018-11-17 05:58:22
【问题描述】:

获得不同货币的用户钱包总余额的最佳方法是什么?

myapp/models.py

from django.db import models
from django.contrib.auth.models import User

USD = 'USD'
EUR = 'EUR'
GBP = 'GBP'
CURRENCY_CHOICES = (
    (USD, 'US Dollars'),
    (EUR, 'Euro'),
    (GBP, 'UK Pounds'),
)

class Wallet(models.Model):
    user = models.ForeignKey(User)
    accnumber = models.CharField(max_length=12)
    currency = models.CharField(choices=CURRENCY_CHOICES, default=EUR)
    balance = models.DecimalField(max_digits=9,decimal_places=2)

货币汇率以字典形式从fixer.io 获得 [(u'usd', 'US Dollars'), (u'eur', 'Euro'), (u'rub', 'Russian Rubles'), (u'gbp', 'UK Pound Sterling'), (u'btc', 'Bitcoin'), (u'eth', 'Etherium')]

myapp/views.py

import requests
from decimal import Decimal
from django.conf import settings
from django.views.generic.base import TemplateView
from django.db.models import Sum
from myyapp.model import Wallet, CURRENCY_CHOICES 

class TotalBalanceView(TemplateView):
    template_name = 'balance.html'

    def get_context_data(self, **kwargs):
        context = super(TotalBalanceView, self).get_context_data(**kwargs)

        #get current exchage rates from Fixer.IO
        symbols = ','.join(dict(CURRENCY_CHOICES).keys()).upper()
        uri = "http://data.fixer.io/api/latest?access_key={}&base=EUR&symbols={}".format(FIXER_API, symbols)
        r = requests.get(uri)
        rates = r.json()['rates']

        #get account for the user
        wallets = Wallet.objects.filter(user=self.request.user)
        total = Decimal()
        for curr in CURRENCY_CHOICES:
            total += wallets.filter(currency=curr).aggregate(
                    total=Sum('balance'))

        context.update({
            'wallets ': wallets
            'total': total_eur + total_usd * rates['USD'] + total_gbp * rates['GBP']
        })

        return context

myapp/templates/balance.html

<h1>Total is: {{ total|floatformat:2 }}</h1>
{% for w in wallets %}
    <p>{{ w.accnumber }}</p>
{% endfor %}

我确信在一个查询请求中使用聚合函数应该有更有效的解决方案

【问题讨论】:

    标签: django django-models aggregate-functions


    【解决方案1】:

    我们基本上可以通过对每种货币执行某种分组来做到这一点:

    totals = (wallets.values('currency')
                     .annotate(total=Sum('balance'))
                     .order_by('currency'))

    这将产生 iterable dictionaries,其中currency 映射到货币,total 映射到该货币的总数。例如:

    [{'currency': 'EUR', 'total': 123.45},
     {'currency': 'USD', 'total': 456.78},
     {'currency': 'BFR', 'total': 901.23}]
    

    然后我们可以将一种货币的总和计算为:

    total = sum([subsum[total] * rate[subsum['currency']]
                 for subsum in totals])
    

    您可能需要为您转换为的货币添加一个汇率(汇率等于1.00)。

    【讨论】:

    • @EgorBolotevich:是的,您需要交换语句,已编辑。
    • @EgorBolotevich:你删除了顶部的values,所以只删除了wallets.order_by(..)...
    • @EgorBolotevich:请使用您使用的代码编辑您的问题。
    • @EgorBolotevich:好的,我想我终于找到了查询的错误。见编辑。
    猜你喜欢
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 2020-10-02
    • 2022-08-08
    • 1970-01-01
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    相关资源
    最近更新 更多