Django комментирует несколько одинаковых объектов в QuerySet разными связанными объектами - PullRequest
0 голосов
/ 26 января 2019

Я получил:

# 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 2 одинаковых профиля. Как я могу аннотировать каждый из них различными flat, например: profiles.first().flat == flat_1 и profiles.last().flat == flat_2?

Может быть Subquery() но как?

UPD Мне это нужно в некоторых списках DRF. Вывод в формате JSON должен выглядеть примерно так:

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

Ответы [ 3 ]

0 голосов
/ 01 февраля 2019

Вам не нужно профилировать экземпляры ...

В конце я написал код для ваших конкретных потребностей, но сначала написал пару вещей, которые могут представлять интерес.

В вашем примере кода вы создали только один профиль, я уверен, что вы не получаете 2 экземпляра профиля, равного , но только один.

Дело в том, что если у вас есть 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
  }
]
0 голосов
/ 03 февраля 2019

Вы можете сделать это с правильным сериализатором и правильной аннотацией:

Сериализатор:

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 } ]

Дайте мне знать, если это работает для вас

0 голосов
/ 28 января 2019

Чтобы получить этот вывод, вы можете сделать:

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

в вашем представлении DRF.

...