Поле «Многие ко многим» и «Вложенный сериализатор» в REST: перезапись Вложенный сериализатор не создает вложенный объект в Django - PullRequest
1 голос
/ 27 июня 2019

У меня есть две модели, имеющие отношение многие ко многим, и я пытаюсь отправить вложенные данные в мой API.К сожалению, он возвращает мне только пустой массив.

Это то, что я пытаюсь:

мои модели:


class Building(models.Model):
    name  = models.CharField(max_length=120, null=True, blank=True)
    net_leased_area = models.FloatField(null=True, blank=True)

class BuildingGroup(models.Model):
    description           = models.CharField(max_length=500, null=True, blank=True)
    buildings             = models.ManyToManyField(Building, default=None, blank=True)

Мое общее представление API:

class BuildingGroupCreateAPIView(CreateAPIView):
    queryset                    = BuildingGroup.objects.all()
    serializer_class            = BuildingGroupSerializer

Мой сериализатор:


class BuildingGroupSerializer(serializers.ModelSerializer):

    buildings = BuildingSerializer(many=True)

    class Meta:

        model = BuildingGroup

        fields = (
            'description',
            'buildings',
        )

    def create(self, validated_data):
        buildings_data = validated_data.pop('buildings')
        building_group = BuildingGroup.objects.create(**validated_data)
        for building_data in buildings_data:
            Building.objects.create(building_group=building_group, **building_data)
        return building_group

Когда я отправляю данные, он возвращает это:


{"description":"Test Description API","buildings":[]}

В массиве я хотел бы иметь свой массив словарей.

Я пытаюсь следовать документации REST здесь, когда перезаписываю метод create для отправки вложенного объекта.(https://www.django -rest-framework.org / api-guide / Relations / # writable-nested-serializers ), и я подумал, что я делаю это правильно, но эпическая ошибка.

Я отправляю данные с запросом с помощью моего пользовательского метода, например:

test_api_local(method="post", data={
        "description": "Test Description API",
        "buildings": [{'name' : 'Testname'}, .... ],
         })

Любая помощь очень ценится.Большое спасибо !!

РЕДАКТИРОВАТЬ: Когда я пытаюсь проверить его в режиме REST, он говорит мне:

TypeError: 'building_group' is an invalid keyword argument for this function

EDIT2: Вот мой взгляд:

class BuildingGroupCreateAPIView(CreateAPIView):
    queryset                    = BuildingGroup.objects.all()
    serializer_class            = BuildingGroupSerializer

    def create(self, request, *args, **kwargs):
        serializer = BuildingGroupSerializer(data=self.request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

1 Ответ

1 голос
/ 01 июля 2019

Вы должны явно получить или создать экземпляры Building, в зависимости от переданных идентификаторов внутри данных полезной нагрузки, а затем добавить их в BuildingGroup экземпляр.

class NestedBuildingSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)

    class Meta:
        model = Building
        fields = '__all__'


class BuildingGroupSerializer(serializers.ModelSerializer):
    buildings = NestedBuildingSerializer(many=True)

    class Meta:
        model = BuildingGroup
        fields = (
            'description',
            'buildings',
        )

    def create(self, validated_data):
        buildings_data = validated_data.pop('buildings')
        building_group = BuildingGroup.objects.create(**validated_data)
        buildings = []  # it will contains list of Building model instance
        for building_data in buildings_data:
            building_id = building_data.pop('id', None)
            building, _ = Building.objects.get_or_create(id=building_id,
                                                         defaults=building_data)
            buildings.append(building)
        # add all passed instances of Building model to BuildingGroup instance
        building_group.buildings.add(*buildings)
        return building_group

class BuildingGroupView(ListAPIView, CreateAPIView):
    queryset = BuildingGroup.objects.all()
    serializer_class = BuildingGroupSerializer


## Assume you add your views like this in urls.py
urlpatterns = [
    .....
    path('building-groups', views.BuildingGroupView.as_view(),
         name='building-group'),
    .....
]

При вызове конечной точки /building-groups как POST метод с полезной нагрузкой, подобный следующему:

{
  "description": "here description",
  "buildings": [
    {
      "id": 1, # existing building of id 1
      "name": "name of building 1",
      "net_leased_area": 1800
    },
    { 
      # a new building will gets create
      "name": "name of building 2",
      "net_leased_area": 1800
    }
  ]
}

Затем он вернет ответ, подобный следующему: -

{
  "description": "here description",
  "buildings": [
    {
      "id": 1,
      "name": "name of building 1",
      "net_leased_area": 1800
    },
    {
      "id": 2
      "name": "name of building 2",
      "net_leased_area": 1800
    }
  ]
}

Узнайте о M2M-связи и, .get_or_create()

Примечание: BuildingSerializer и NestedBuildingSerializer различны.Не путайте их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...