我有一个网页,其中显示了一些卖家和客户之间交易的报告。因此,为了这个目的,我需要创建一个 API 来从数据库中获取所有交易,提取必要的数据并将它们序列化以在网页中有用。所以我不想创建任何模型,只是以 JSON 格式返回数据。
首先我像这样创建了我的序列化器:
from rest_framework import serializers
from django.db.models import Sum, Count
from account.models import User
class IncomingTradesSerializer(serializers.Serializer):
all_count = serializers.IntegerField()
all_earnings = serializers.IntegerField()
successful_count = serializers.IntegerField()
successful_earnings = serializers.IntegerField()
def __init__(self, *args, **kwargs):
self.trades = kwargs.pop('trades', None)
super().__init__(*args, **kwargs)
def get_all_count(self, obj):
return self.trades.count()
def get_all_earnings(self, obj):
return sum(trade.trade_price for trade in self.trades)
def get_successful_count(self, obj):
return self.trades.exclude(failure_reason=None).count()
def get_successful_earnings(self, obj):
return sum(trade.trade_price for trade in self.trades.exclude(failure_reason=None))
class TradesDistributionSerializer(serializers.Serializer):
sellers = serializers.DictField()
def __init__(self, *args, **kwargs):
self.trades = kwargs.pop('trades', None)
super().__init__(*args, **kwargs)
def get_sellers(self, obj):
sellers = {}
for user in User.objects.all():
distributed_trades = self.trades.filter(creator=user)
sellers[user.username] = sum(
trade.trade_price for trade in distributed_trades)
return sellers
然后我的
apiView
看起来像这样:
from rest_framework.views import APIView
from rest_framework.response import Response
from trade.models import Trade
from report.serializers import IncomingTradesSerializer, TradesDistributionSerializer
class IndicatorView(APIView):
def get(self, request):
trades = Trade.objects.all()
incoming_trades_serializer = IncomingTradesSerializer(trades=trades)
trades_distribution_serializer = TradesDistributionSerializer(trades=trades)
results = {
'incomingTrades': incoming_trades_serializer.data,
'tradesDistribution': trades_distribution_serializer.data
}
return Response(results)
问题出在
get_fieldname
未调用的方法中,因此最后的响应由 null 或空值组成:
{
"incomingTrades": {
"all_count": null,
"all_earnings": null,
"successful_count": null,
"successful_earnings": null
},
"tradesDistribution": {
"sellers": {}
}
}
我已经将
integerField
和 DictField
更改为 MethodField
但问题没有解决,唯一的变化是字段响应消失了,唯一的东西是序列化器的两个空字典。
我尝试的另一种方法是重写
to_representation
方法,但和以前一样(当然我的经理告诉我,如果字段数量增加,这种方法性能不好)。
有什么问题吗?
我是否需要改变我的方法或做一些事情,例如覆盖另一种方法或其他方法?
这种情况的标准方法是什么?
SerializerMethodField
并且坚持使用 Django ORM 来获取所需的数据而不是迭代它:
views.py
class IndicatorView(APIView):
def get(self, request):
serializer = IndicatorSerializer(Trade.objects.all())
return Response(serializer.data)
序列化器.py
class IndicatorSerializer(serializers.Serializer):
incoming_trades = serializers.SerializerMethodField()
trades_distribution = serializers.SerializerMethodField()
def get_incoming_trades(self, trades):
"""
If there is a reason for failure then .exclude(failure_reason=None)
would yield UNSUCCESFULL trades.
Thus, if you want successfull ones, that would be:
.filter(failure_reason=None).count()
"""
incoming_trades = {
'all_count': trades.count(),
'all_earnings': trades.aggregate(total=Sum("trade_price"))['total'],
'successful_count': trades.filter(failure_reason=None).count(),
'successful_earnings': (
trades.filter(failure_reason=None)
.aggregate(total=Sum("trade_price"))['total']),
'unsuccessful_count': trades.exclude(failure_reason=None).count(),
'unsuccessful_earnings': (
trades.exclude(failure_reason=None)
.aggregate(total=Sum("trade_price"))['total']),
}
return incoming_trades
def get_trades_distribution(self, trades):
"""
Note that just like your query
this does not distinguish successful / unsuccessful trades
Therefore, you should filter the QS if that is your intention.
"""
trades_distribution =(
trades.order_by("id")
.annotate(seller=F("creator__username"))
.values("seller")
.annotate(trades_total=Sum("trade_price"))
.order_by()
)
return trades_distribution
回应
{
"incoming_trades": {
"all_count": 3,
"all_earnings": 733.76,
"successful_count": 2,
"successful_earnings": 165.87,
"unsuccessful_count": 1,
"unsuccessful_earnings": 567.89
},
"trades_distribution": [
{
"seller": "admin",
"trades_total": 691.34
},
{
"seller": "someuser",
"trades_total": 42.42
}
]
}