gpt4 book ai didi

Django REST 框架序列化程序 : Display the latest object of a reverse relationship

转载 作者:行者123 更新时间:2023-12-01 00:50:56 25 4
gpt4 key购买 nike

ListAPIView(下面的代码)的默认行为是序列化所有 Report 对象和每个 Report 对象的嵌套 Log 对象。如果我只希望每个报告显示最新的日志对象怎么办?我该怎么做?

# models.py
class Log(models.Model):
# ...
report = models.ForeignKey(Report)
timestamp = models.DateTimeField(default=datetime.datetime.now)

class Report(models.Model):
code = models.CharField(max_length=32, unique=True)
description = models.TextField()


# serializers.py
class LogSerializer(serializers.ModelSerializer):

class Meta:
model = Log

class ReportSerializer(serializers.ModelSerializer):
log_set = LogSerializer(many=True, read_only=True)

class Meta:
model = Report
fields = ('code', 'description', 'log_set')


# views.py
class ReportListView(generics.ListAPIView):

queryset = Report.objects.all()
serializer_class = ReportSerializer

我知道我可以通过使用 SerializerMethodField 来做到这一点,但这可能是一个潜在的昂贵操作,因为会有一个额外的 SQL 查询来为每个 Report 对象检索适当的 Log 对象。
class ReportSerializer(serializers.ModelSerializer):
latest_log = serializers.SerializerMethodField()

class Meta:
model = Report

def get_latest_log(self, obj):
try:
latest_log = Log.objects.filter(report_id=obj.id).latest('timestamp')
except Log.DoesNotExist:
latest_log = None
return latest_log

如果我有 1000 个报告对象,如果我想全部呈现它们,将会有 1000 个额外的查询。除了使用分页之外,如何避免这些额外的查询?任何人都可以指出我正确的方向吗?谢谢!

编辑:关于可能的重复标签,仅马克提供的链接并没有为我完全清除图片。托多尔的回答更加明确。

最佳答案

您需要以某种方式注释 latest_logReportQuerySet ,因此它可以被序列化程序使用而无需进行任何额外的查询。

实现此目的的最简单方法是通过 prefetching所有的logsreport .这种方法的缺点是您将所有 logs 加载到内存中。每 report每页。如果有一个 report 哪个还不错得到类似 5-10-15 logs .这意味着对于具有 50 reports 的页面, 你要加载 50*10=500 logs这没什么大不了的。如果还有更多logsreport (假设为 100)那么您需要对 queryset 进行额外过滤.

下面是一些示例代码:

  • 预取 logs .
    # views.py
    class ReportListView(generics.ListAPIView):

    queryset = Report.objects.all()\
    .prefetch_related(Prefetch('log_set',
    queryset=Log.objects.all().order_by('-timestamp'),
    to_attr='latest_logs'
    ))
    serializer_class = ReportSerializer
  • 创建一个辅助方法以方便访问 latest_log
    class Report(models.Model):
    #...

    @property
    def latest_log(self):
    if hasattr(self, 'latest_logs') and len(self.latest_logs) > 0:
    return self.latest_logs[0]
    #you can eventually implement some fallback logic here
    #to get the latest log with a query if there is no cached latest_logs
    return None
  • 最后序列化程序只使用属性
    class ReportSerializer(serializers.ModelSerializer):
    latest_log = serializers.LogSerializer()

    class Meta:
    model = Report
  • logs 的更高级过滤示例可以是这样的:
    Report.objects.all().prefetch_related(Prefetch('log_set', queryset=Log.objects.all().extra(where=[
    "`myapp_log`.`timestamp` = (\
    SELECT max(timestamp) \
    FROM `myapp_log` l2 \
    WHERE l2.report == `myapp_log`.`report`\
    )"]
    ), to_attr='latest_logs'
    ))

    关于Django REST 框架序列化程序 : Display the latest object of a reverse relationship,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31424249/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com