【问题标题】:Queryset in one to many relation一对多关系中的查询集
【发布时间】:2020-12-05 06:25:40
【问题描述】:

我正在尝试获取 Json 元素及其相关元素

我有两张桌子,ServiceRoom。一项服务有许多房间。我想得到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'

序列化器

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__'

查看

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?

【问题讨论】:

    标签: python django django-rest-framework django-queryset


    【解决方案1】:

    您可以通过添加带有过滤查询集的 custom Prefetch object [Django-doc] 来修补集合,例如:

    from django.db.models import Prefetch
    
    queryset = Service.objects.filter(
        room__id=1
    ).prefetch_related(
        Prefetch('room_set', queryset=Room.objects.filter(id=1), to_attr='room_set1')
    )
    serializer = ServiceSerializer(queryset, many=True)
    return JsonResponse(serializer.data, safe=False)

    Serializer解析新的相关经理:

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

    【讨论】:

    • 感谢 Willem,但此解决方案返回错误:TypeError:禁止直接分配到相关集的反面。请改用 room_set.set()。我已将 to_attr='room_set' 更改为 to_attr='room_set.set()' 并且结果与我一开始得到的结果相同,而不是我期望的结果。
    • @user1818759:如果将to_attr 重命名为room_set1 会怎样。
    • 是的,现在它可以工作了,但是在 ServiceSerializer 中,字段必须是 'room_set' 而不是 'room_set1'。谢谢
    【解决方案2】:

    您可以通过序列化程序上下文传递房间 ID,并在 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 的回答很简短,但它也需要两个与我相同的查询。

    【讨论】:

      猜你喜欢
      • 2015-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-30
      • 2019-01-04
      • 2011-06-23
      • 2016-06-10
      相关资源
      最近更新 更多