Queryset в отношении один ко многим - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь получить Json элементов со связанными с ними элементами

У меня было две таблицы, Service и Room. Один сервис имеет много номеров. Я хотел бы получить услугу, где есть room_id = x.

Модель

class Service(models.Model):
    name = models.CharField(max_length=255, blank=True, null=True)
    class Meta:
        managed = True
        db_table = 'Service'

class Room(models.Model):
    name = models.CharField(max_length=255, blank=True, null=True)
    service = models.ForeignKey(Service, models.DO_NOTHING, blank=True, 
    null=True)
    class Meta:
        managed = True
        db_table = 'Room'

Serializer

class ServiceSerializer(serializers.ModelSerializer):
    room_set = RoomSerializer(many=True, read_only=True)
    class Meta:
       model = Service
       fields = ('name','room_set')
class RoomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Room        
        fields = '__all__'

View

queryset = Service.objects.filter(room__id=1)
serializer = ServiceSerializer(queryset, many=True)
return JsonResponse(serializer.data, safe=False)

Я ожидаю, что Json вот так:

{
     "name": "Hotel1",
     "room_set": [
     {
           "id": 1,
           "name": "Room1"
      },

Но я получаю это:

 {
     "name": "Hotel1",
     "room_set": [
     {
           "id": 1,
           "name": "Room1",
      },
      {
            "id": 2,
            "name": "Room2",
      },
      {
             "id": 3,
             "name": "Room3",
      }
  } 

Можно ли получить json, такой как я ожидал?

Ответы [ 2 ]

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

Вы можете передать идентификатор комнаты через контекст сериализатора и соответственно отфильтровать внутри SerializerMethodField ()

class ServiceSerializer(serializers.ModelSerializer):
    rooms = serializers.SerializerMethodField()
    class Meta:
       model = Service
       fields = ('name','rooms')

    get_rooms(self,service):
       room_id = self.get_context('room')
       if room_id:
         queryset = service.rooms_set.filter(id=room_id)
         return RoomSerializer(queryset,many=True).data
       return RoomSerializer(service.rooms_set.all(),many=True).data

serializer = ServiceSerializer(queryset, many=True,context={'room':1})
return JsonResponse(serializer.data, safe=False)

Вот как это сделать через сериализатор, и он очень настраиваемый, Willem Van Onsem * Ответ 1007 * достаточно короткий, но он также требует двух запросов, таких же, как у меня.

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

Вы можете исправить набор, добавив custom Prefetch объект [Django-doc] с отфильтрованным набором запросов, например:

from django.db.models import Prefetch

queryset = Service.objects.filter(
    room__id=1
).prefetch_related(
    Prefetch('room_set', queryset=<b>Room.objects.filter(id=1)</b>, to_attr=<b>'room_set1'</b>)
)
serializer = ServiceSerializer(queryset, many=True)
return JsonResponse(serializer.data, safe=False)

и пусть Serializer анализирует нового связанного менеджера:

class ServiceSerializer(serializers.ModelSerializer):
    room_set = RoomSerializer(many=True, read_only=True<b>, source='room_set1'</b>)
    class Meta:
       model = Service
       fields = ('name','room_set1')
class RoomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Room        
        fields = '__all__'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...