Как в Django построить сериализатор, который захватывает данные в объединенной таблице?

Я использую Python 3.9 и Django 3.2. У меня есть несколько моделей - модель Coop, которая имеет много моделей Address, связанных через таблицу join (CoopAddressTags)

class Coop(models.Model):
    objects = CoopManager()
    name = models.CharField(max_length=250, null=False)
    addresses = models.ManyToManyField(Address, through='CoopAddressTags')
    enabled = models.BooleanField(default=True, null=False)
    web_site = models.TextField()
    description = models.TextField(null=True)
    approved = models.BooleanField(default=False, null=True)
       self.save()  

class CoopAddressTags(models.Model):
    # Retain referencing coop & address, but set "is_public" relation to NULL
    coop = models.ForeignKey(Coop, on_delete=models.SET_NULL, null=True)
    address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True)
    is_public = models.BooleanField(default=True, null=False)

Я хотел бы создать сериализатор, который может анализировать данные, отправленные из внешнего приложения, а затем сохранять эти отношения,

class Coop(APIView):
    ...
    def post(self, request, format=None):
        serializer = CoopSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()

но я не могу понять, как включить часть уравнения, связанную с таблицей объединений. В частности, я не знаю, как захватить поле "is_public" из таблицы join в сериализаторе и затем сохранить все, поскольку для таблицы join необходимо, чтобы существовали модели Coop и Address. У меня есть следующее

class CoopSerializer(serializers.ModelSerializer):
    addresses = AddressSerializer(many=True)

    class Meta:
        model = Coop
        fields = '__all__'

    def to_representation(self, instance):
        rep = super().to_representation(instance)
        rep['addresses'] = AddressSerializer(instance.addresses.all(), many=True).data
        return rep

    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return self.save_obj(validated_data=validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Coop` instance, given the validated data.
        """
        return self.save_obj(instance=instance, validated_data=validated_data)

    def save_obj(self, validated_data, instance=None):
        addresses = validated_data.pop('addresses', {})
        if not instance:
            instance = super().create(validated_data)
        for address in addresses:
            serializer = AddressSerializer()
            addr = serializer.create_obj(validated_data=address)
            instance.addresses.add(addr)
        instance.name = validated_data.pop('name', None)
        instance.web_site = validated_data.pop('web_site', None)
        instance.save()
        return instance

Проблема в том, что когда это сохраняется, "is_public" всегда по умолчанию равен true, потому что я не знаю, как отправить его через JSON и перехватить его в сериализаторе. Благодарен за любой совет.

Попробуйте прочитать о вложенном сериализаторе -

Определите свои модели как -

class Coop(models.Model):
    ---
    ---

и в модели CoopAddressTags добавить related_name для coop

class CoopAddressTags(models.Model):
    coop = models.ForeignKey(Coop, on_delete=models.SET_NULL, null=True, related_name="xyz")
    ---
    ---

и затем - сначала определите CoopAddressTags_serializer как обычно, а затем coop_serializer как -

class CoopSerializer(serializers.ModelSerializer):
    xyz = CoopAddressTags_serializer(many=True)
    # by default this is read only

    class Meta:
        model = Coop
        fields = ('id', 'xyz')
        # include all the field of coop model

до сих пор, когда вы посетите localhost:8000/coop, вы получите все объекты coopaddress, связанные с экземпляром coop. Теперь для постинга напишите метод create сериализатора coop в виде -

class coop_serializer(serializers.ModelSerializer):
    ---
    ---

    def create(self, validated_data):
        xyz = validated_data.pop("xyz")
        #pass coop_address as list data along with coop data as xyz
        coop_object = Coop.objects.create(**validated_data)
        for each in xyz:
            CoopAddressTags.objects.create(coop=coop_object, **each)
        return coop_object

Таким же образом напишите метод обновления в соответствии с вашими требованиями.

Вернуться на верх