Как в 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
Таким же образом напишите метод обновления в соответствии с вашими требованиями.