DRF: правильный способ использования ListCreateAPIView с вложенным сериализатором - PullRequest
0 голосов
/ 30 марта 2020

Я создаю страницу со списком всех существующих поставщиков и модулей, которые применяются к каждому поставщику. Здесь мне нужно изменить статус модулей (активный или неактивный), и если модуль не существует, но нужно сделать его активным, то создайте его. Это выглядит примерно так.

Vendor1   module1/false  module2/true   module3/true .....
Vendor2   module1/false  module2/true   module3/true .....
.....
.....

models.py

class RfiParticipation(models.Model):
    vendor = models.ForeignKey('Vendors', models.DO_NOTHING, related_name='to_vendor')
    m = models.ForeignKey('Modules', models.DO_NOTHING, related_name='to_modules')
    active = models.BooleanField(default=False)
    user_id = models.IntegerField()
    rfi = models.ForeignKey('Rfis', models.DO_NOTHING, related_name='to_rfi', blank=True, null=True)
    timestamp = models.DateTimeField(auto_now=True)

Для его отображения я использую класс ListCreateAPIView () и вложенный сериализатор

сериализатор .py

class VendorModulesListManagementSerializer(serializers.ModelSerializer):
    to_vendor = RfiParticipationSerializer(many=True)

    class Meta:
        model = Vendors
        fields = ('vendorid', 'vendor_name', 'to_vendor',)
        read_only_fields = ('vendorid', 'vendor_name', )

    def create(self, validated_data):
        validated_data = validated_data.pop('to_vendor')
        for validated_data in validated_data:
            module, created = RfiParticipation.objects.update_or_create(
                rfi=validated_data.get('rfi', None),
                vendor=validated_data.get('vendor', None),
                m=validated_data.get('m', None),
                defaults={'active': validated_data.get('active', False)})
        return module


class RfiParticipationSerializer(serializers.ModelSerializer):

    class Meta:
        model = RfiParticipation
        fields = ('pk', 'active', 'm', 'rfi', 'vendor', 'timestamp')
        read_only_fields = ('timestamp', )

views.py

class AssociateModulesWithVendorView(generics.ListCreateAPIView):
    """
    RFI: List of vendors with participated modules and modules status
    """
    permission_classes = [permissions.AllowAny, ]
    serializer_class = VendorModulesListManagementSerializer
    queryset = Vendors.objects.all()

У меня есть вопрос об использовании метода create serializer при отправке запроса POST.

Теперь формат ввода выглядит следующим образом

{
    "to_vendor": [
            {
                "active": false,
                "m": 1,
                "rfi": "20R1",
                "vendor": 15

            }]
}

Т.е. ключом словаря для текущей реализации кода является список из одного словаря. Если я удаляю «[]» из значения dict, я получаю

{
    "to_vendor": {
        "non_field_errors": [
            "Expected a list of items but got type \"dict\"."
        ]
    }
}

И по этой причине мне нужно добавить для l oop в методе создания, чтобы перебрать список только с одним элементом , У меня уже есть сомнения, что я поступаю правильно. Может быть, я выбрал неправильный способ реализации?

Но теперь вопрос, почему я получаю ошибку?

AttributeError: Got AttributeError when attempting to get a value for field `to_vendor` on serializer `VendorModulesListManagementSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `RfiParticipation` instance.
Original exception text was: 'RfiParticipation' object has no attribute 'to_vendor'.

Буду очень признателен за вашу помощь и совет!

upd

Получить данные формата запроса:

[
    {
        "vendorid": 15,
        "vendor_name": "Forest Gamp",
        "to_vendor": [
            {
                "pk": 35,
                "active": true,
                "m": "Sourcing",
                "rfi": "1",
                "vendor": 15,
                "timestamp": "2020-03-29T08:15:41.638427"
            },
            {
                "pk": 39,
                "active": false,
                "m": "CLM",
                "rfi": "20R1",
                "vendor": 15,
                "timestamp": "2020-03-29T09:09:03.431111"
            }
        ]
    },
    {
        "vendorid": 16,
        "vendor_name": "Test21fd2",
        "to_vendor": [
            {
                "pk": 41,
                "active": false,
                "m": "SA",
                "rfi": "20R1",
                "vendor": 16,
                "timestamp": "2020-03-30T11:05:16.106412"
            },
            {
                "pk": 40,
                "active": false,
                "m": "CLM",
                "rfi": "20R1",
                "vendor": 16,
                "timestamp": "2020-03-30T10:40:52.799763"
            }
        ]
    }
]

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Он пытается получить доступ к to_vendor в вашей модели RfiParticipation и жалуется, что это свойство не существует. related_name относится к обратной связи на вашей Vendors модели. Так что вы можете сделать что-то вроде Vendors.to_vendor.all() и извлечь все RfiParticipation экземпляры.

Это происходит, когда он пытается проверить ваши входные данные, так что даже до того, как он попадет в функцию создания вашего сериализатора.

Если вы пытаетесь создать новый RfiParticipation, зачем вам использовать представление, определяющее queryset = Vendors.objects.all()?

Вместо определения представления, которое заботится о создании RfiParticipation, так как оно кажется что у вас уже есть ссылка на Vendors. Если я правильно понимаю, то, что вы пытаетесь сделать, это в основном пакетное создание RfiParticipation, поэтому создайте представление, которое указывает на это.

0 голосов
/ 31 марта 2020

Я прошел через вашу реализацию, и я полагаю, вы, возможно, использовали неверное наследование класса обобщенных данных в views.py.

Вы должны попытаться заменить

class AssociateModulesWithVendorView(generics.ListCreateAPIView):
    permission_classes = [permissions.AllowAny, ]
    serializer_class = VendorModulesListManagementSerializer
    queryset = Vendors.objects.all()

С

class AssociateModulesWithVendorView(generics.CreateAPIView, generics.ListAPIView):
    permission_classes = [permissions.AllowAny, ]
    serializer_class = VendorModulesListManagementSerializer
    queryset = Vendors.objects.all()

Вы можете проверить ссылки ниже для ссылки: CreateAPIView: https://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin ListCreateAPIView: https://www.django-rest-framework.org/api-guide/generic-views/#listcreateapiview

...