为了账号安全,请及时绑定邮箱和手机立即绑定

序列化DRF中的相关字段

序列化DRF中的相关字段

陪伴而非守候 2021-05-31 06:01:01
我有两个模型,一个父模型和一个子模型,我想存在于数据库的不同表中,但是当我返回到客户端时,它们在同一对象(平面)上表示它们。我已经尝试了一些选项,包括 SerializerMethodFields (SMF) 和 ReadOnlyFields,但它们都会导致太多的数据库查询。我还尝试过嵌套对象,然后稍后对其进行展平,这确实起作用,但是由于Django的序列化程序的工作方式,导致产生了更多的代码。这让我觉得应该有更好的方法来实现这一目标。下面是使用 SMF 方法调用序列化程序的示例:# in the viewclass ListFoo(APIView):    def get(self, request):        foo = Foo.objects.prefetch_related('bar').all()        serializer = FooSerializer(foo, may=True)        Response(serializer.data, status=status.HTTP_200_OK)# in the serializerclass FooSerializer(ModelSerializer):    employer = SerializerMethodField()    position = SerializerMethodField()    class Meta:        model = Foo        fields('id', 'name', 'employer', 'position')    def get_employer(self, foo):        # use related manager to access related object        return foo.bar.last().employer    def get_position(self, foo):        # use related manager to access related object        return foo.bar.last().position# in the modelsclass Foo(models.Model):    name = models.CharField(max_length=150)class Bar(models.Model):    employer = models.CharField(max_length=150)    position = models.CharField(max_length=150)    foo = models.ForeignKey(        Foo,        related_name='bar',        unique=False,        on_delete=models.CASCADE    )现在上面的代码有效,但是如果我查询许多 Foo 对象,它将查询 +1 bar 我需要从 bar 访问的每个属性。我正在尝试找到一种在全局化存储/缓存数据的方式,当序列化程序初始化时,我可能会查询该数据。对更有效或更有效的方法有什么想法吗?更新:我基本上已经弄清楚了,明天将发布解决方案。我没有意识到有多少方法可以对使用预取创建的查询集进行不当操作。
查看完整描述

2 回答

?
茅侃侃

TA贡献1842条经验 获得超21个赞

不太确定,我明白,但看起来你想要你的 Foo 对象的最后一个雇主。那么你的 SerializerMethodField 可能如下(假设这里创建日期降序反映了你最近的雇主)


def get_employer(self, foo):

   obj= foo.bar.all().order_by('-created')[0]

   return obj.employer


查看完整回答
反对 回复 2021-06-01
?
慕桂英546537

TA贡献1848条经验 获得超10个赞

上面的代码的问题是,当我使用最后一种方法对queryset进行操作时


def get_employer(self, foo):

    # use related manager to access related object

    return foo.bar.last().employer

每次get_employer调用时,Django 都会查询数据库。阅读文档和其他几个答案后,我意识到使用该all()方法是重要的下一步,因为它将返回相关对象的查询集(在视图中预取)。令我感到奇怪的是,您不能像通常使用类似last()or的方法那样直接对相关对象进行操作,filter()但您可以遍历它们并进行过滤。


解决我的问题所需要做的就是返回 related_manager 查询集中的最后一项,我通过使用下标返回查询集中的最后一个对象来完成此操作。我敢肯定,有一些方法可以减少代码,但是它可以工作。


def get_employer(self, foo):

    qs = foo.bar.all()

    last = query.count()

    obj = model_to_dict(qs[last-1])


    return obj.get('employer')


查看完整回答
反对 回复 2021-06-01
  • 2 回答
  • 0 关注
  • 179 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号