Django通过不同的相关对象在QuerySet中注释几个相同的对象

时间:2019-01-26 09:35:50

标签: django django-models django-queryset django-annotate

我知道了

# models

class Building(models.Model):
    ...


class Flat(models.Model):
    building = models.ForeignKey(Building)


class Profile(models.Model):
    flats = models.ManyToManyField(Flat)
# logic

building = Building.objects.create()
flat_1 = Flat.objects.create(building=building)
flat_2 = Flat.objects.create(building=building)

profile = Profile.objects.create()
profile.flats.add(flat_1)
profile.flats.add(flat_2)

profiles = Profile.objects.filter(flats__building=building)  

我有profiles两个相同的个人资料。我如何用不同的flat来对每个注释进行注释,例如:profiles.first().flat == flat_1profiles.last().flat == flat_2

也许Subquery(),但如何?

UPD 在某些DRF列表视图中需要此功能。 JSON中的输出必须类似于:

[
  {
    "profile_id": 1,
    "flat_id": 2
  },
  {
    "profile_id": 1,
    "flat_id": 3
  }
]

3 个答案:

答案 0 :(得分:2)

要获取该输出,您可以执行以下操作:

data = Profile.objects.all().values('flats', 'id')
return Response(data=data)

在您的DRF视图中。

答案 1 :(得分:0)

您不必分析实例...

  

最后,我为满足您的确切需求编写了代码,但首先写了几篇有趣的文章。

在您的代码示例中,您仅创建了一个配置文件,我确定您不会得到 2个相等的Profile实例,而只有一个。

问题是,如果您有一个只有一个条目的QuerySet,则:

profiles.first() == profiles.last()  # True

因为profile.first()profiles.last()是同一实例。

您应该尝试创建2个配置文件实例:

building = Building.objects.create()

flat_1 = Flat.objects.create(building=building)
flat_2 = Flat.objects.create(building=building)

profile_1 = Profile.objects.create()  # You coud/should use bulk_create here.
profile_2 = Profile.objects.create()

profile_1.flats.add(flat_1)
profile_2.flats.add(flat_2)

然后

profiles = Profile.objects.filter(flats__building=building)  

将返回两个不同的配置文件对象。

另一方面,根据需要获取JSON ...

在此示例之后,您发布并按配置文件过滤单位并获取值(如果您拥有一个以上的配置文件,这也适用)。

Flat.objects.filter(profile=profile_1).values('profile__id', 'id')

这将返回类似(“ id”代表单位id s)的信息:

[
  {
    "profile__id": 1,
    "id": 1
  },
  {
    "profile__id": 1,
    "id": 3
  }
]

如果您不按个人资料过滤(并且有多个),则可能会得到类似的内容:

[
  {
    "profile__id": 1,
    "id": 1
  },
  {
    "profile__id": 2,
    "id": 3
  },
  {
    "profile__id": 2,
    "id": 4
  },
  ...
]

注释获取所需的精确json:

如前所示的过滤器添加注释,并获得所需的值:

Flat.objects.filter(profile=profile_1).annotate(
    flat_id=F('id')
).annotate(
    profile_id=F('profile__id')
).values(
    'profile_id', 'flat_id'
)

将准确给出您想要的:

[
  {
    "profile_id": 1,
    "flat_id": 2
  },
  {
    "profile_id": 1,
    "flat_id": 3
  }
]

答案 2 :(得分:0)

您可以使用正确的序列化器和正确的批注进行操作:

序列化器:

class FlatSerializer(serializers.ModelSerializer):
    class Meta:
        model = Flat
        fields = ('flat_id', 'building_id')

    flat_id = serializers.CharField(read_only=True)

然后,我只查询Flats而不是配置文件并进行序列化:

flats = Flat.objects \
    .annotate(flat_id=F('id')) \
    .filter(building=building)

serialized = FlatSerializer(flats, many=True)
print(serialized.data) # [ { flat_id: 1, building_id: 1 }, { flat_id: 2, building_id: 1 } ]

让我知道这是否对您有用