Сериализатор поля списка, дающий объект ManyRelatedManager, не является повторяемой ошибкой с полем M2M - PullRequest
0 голосов
/ 26 сентября 2018

Мой models.py выглядит следующим образом:

class IP(models.Model):
    name = models.CharField(max_length=30, unique=True)
    address = models.CharField(max_length=50, unique=True)

class IPGroup(models.Model):
    name = models.CharField(max_length=50, unique=True)
    ips = models.ManyToManyField('IP', through='IPGroupToIP')

class IPGroupToIP(BaseModel):
    ip_group = models.ForeignKey('IPGroup', on_delete=models.CASCADE)
    ip = models.ForeignKey('IP', on_delete=models.CASCADE)

Теперь для создания IPGroup у меня есть следующий сериализатор:

class IPGroupCreateSerializer(serializers.ModelSerializer):
    ips = serializers.ListField()

class Meta:
    model = IPGroup
    fields = ['name', 'ips']

@transaction.atomic()
def create(self, validated_data):
    ips_data = validated_data.pop('ips', None)
    ip_group = IPGroup.objects.create(name=validated_data['name'])

    if ips_data:
        for ip in ips_data:
            ip_obj, created = IP.objects.get_or_create(name=ip['name'], address=ip['address'])
            IPGroupToIP.objects.create(ip_group_id=ip_group.id, ip_id=ip_obj.id)
    return ip_group

Мои представления - простой классна основе представления следующим образом:

class IPGroupCreateView(generics.CreateAPIView):
    queryset = IPGroup.objects.get_queryset()
    serializer_class = IPGroupCreateSerializer

Моя полезная нагрузка JSON выглядит следующим образом:

{"ips": [{"name": "example.com", "address": "10.1.1.9"}], "name": "ipgroup1"}

Как бы то ни было, я получаю сообщение об ошибке:

TypeError at / api / v1/ ip-group /
Объект ManyRelatedManager не повторяется

Странно то, что когда я проверяю БД, IPGroup создается вместе с M2M ips.Итак, код работает должным образом, но представление каким-то образом возвращает ошибку 500 серверов вместо созданного 201.Что я делаю не так?

1 Ответ

0 голосов
/ 26 сентября 2018

Из-за некоторых сложностей ListField() станет полезным только при записи в БД (я не уверен, почему такое поведение).

В вашем контексте добавление write_only=True в ListField решит исключение.Следовательно, IPGroupCreateSerializer будет иметь вид

class IPGroupCreateSerializer(serializers.ModelSerializer):
    ips = serializers.ListField(<b>write_only=True</b>)



Я лично рекомендую использовать Вложенные сериализаторы чтобы справиться с этой ситуацией.Итак, определите новый класс IPSerializer и используйте его вместо serializers.ListField()

<b>class IPSerializer(serializers.ModelSerializer):
    class Meta:
        model = IP
        fields = ('name', 'address')</b>


class IPGroupCreateSerializer(serializers.ModelSerializer):
    <b>ips = IPSerializer(many=True)</b>


class Meta:
    model = IPGroup
    fields = ['name', 'ips']
...