Вложенные сериализаторы создают метод для каждого сериализатора
У меня есть клубная модель, а также адресная модель.
class Club(models.Model):
name = models.CharField(max_length=100)
owner = models.ForeignKey(UserAccount,on_delete=models.CASCADE,related_name = 'owner_of')
##members = models.ManyToManyField(UserAccount,related_name = 'member_of')
##staff = models.ManyToManyField(UserAccount,related_name = 'staff_of')
def __str__(self):
return f'{self.name}'
class Address(models.Model):
name = models.CharField(max_length=100)
street = models.CharField(max_length=150)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100, blank=True, null=True) # Optional for countries without states
province = models.CharField(max_length=100, blank=True, null=True) # Optional for countries without provinces
country = models.CharField(max_length=50)
postal_code = models.CharField(max_length=20)
club = models.ForeignKey(Club,on_delete=models.CASCADE,related_name = 'address')
def __str__(self):
return f'{self.name}'
У них есть свои уважаемые сериализаторы.
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = ['id', 'name', 'street', 'city', 'state', 'province', 'postal_code', 'country']
def create(self,validated_data):
user=self.context['user']
club=Club.objects.get(owner=user)
address=Address.objects.create(club=club,**validated_data)
return address
class ClubSerializer(serializers.ModelSerializer):
class Meta:
model = Club
fields = ['id', 'name']
def create(self,validated_data):
user=self.context['user']
club=Club.objects.create(owner=user,**validated_data)
return club
class ClubRegistrationSerializer(serializers.Serializer):
address= AddressSerializer2()
club=ClubSerializer2()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# We pass the "upper serializer" context to the "nested one"
self.fields['address'].context.update(self.context)
self.fields['club'].context.update(self.context)
вот данные, которые я размещаю
{
"club":{"name":"someclub"},
"address":{
"name":"Bodrum Location",
"street":"140",
"city":"bodrum",
"state":"california",
"province":"some provence",
"postal_code":"123",
"country":"USA"
}
}
Я могу легко реализовать метод create моего представления и
сделайте следующее:
@action(detail=False,methods=['post'])
def register(self, request):
serializer = ClubRegistrationSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
clubinfo_data=serializer.validated_data.pop("club")
club_serializer=ClubSerializer(data=clubinfo_data)
club_serializer.is_valid(raise_exception=True)
club=club_serializer.save(owner=self.request.user)
address_data=serializer.validated_data.pop("address")
address_serializer=AddressSerializer(data=address_data)
address_serializer.is_valid(raise_exception=True)
address=address_serializer.save(club=club)
response={}
response['address']={}
response['address']['name']=address.name
response['address']['id']=address.id
response['address']['postal_code']=address.postal_code
response['club']={}
response['club']['name']=club.name
response['club']['id']=club.id
return Response(response, status=status.HTTP_201_CREATED)
- Но из того, что я читал, следует, что не идеально делать логику в представлениях, а в сериализаторах. Поэтому я могу перенести метод create из create моего представления в create сериализатора. Но что мне не понятно, так это то, что я не могу вызвать метод create вложенных сериализаторов. На самом деле я даже не могу получить объекты вложенного сериализатора, чтобы вызвать его метод create. Вы можете думать об этом так, как будто вы обходите дерево и вызываете методы create каждого сериализатора, и если у них есть create, то они вызывают его дочерний объект.
В идеале я не должен реализовывать всю логику в методе create сериализатора ClubRegistrationSerializer. Каждый сериализатор должен отвечать за свою собственную.
Я должен иметь возможность вызвать метод create сериализатора ClubRegistrationSerializer, который должен вызвать метод create сериализаторов Address и Club.
В каждом примере, который я вижу, вся логика обрабатывается в create родительского сериализатора.
- Во-вторых, как я могу вызвать ClubRegistrationSerializer с адресом obj и клубом obj и получить данные для отправки их пользователю, чтобы в ответе были указаны идентификаторы.
Я пробовал ClubRegistrationSerializer(address=addressOBJ,club=clubOBJ)
вот так
но это приводит к исключению.
В настоящее время я создаю дикту и присоединяю к ней значения модели.
Вот ответ, который я хотел бы получить от сериализатора.
{"club":{"name":"someclub","id":"1"},
"address":{
"id":"1",
"name":"Some Location",
"street":"140",
"city":"San Fran",
"state":"california",
"province":"some province",
"postal_code":"123",
"country":"USA"
}
}
Вам нужно думать о реализации, как о сети отношений.
Прежде всего, вы можете рефакторизовать поле club = models.ForeignKey
в поле отношения OneToOne.
Затем вы можете избавиться от основной обертки dict в полезной нагрузке и реализовать клубные поля flat и поле адреса как dict.
Метод сериализатора .create
только создает новые экземпляры методом Model.objects.create
под капотом, так что вам не нужно вызывать этот метод serializers.create. Валидация полей является наиболее важной в сериализаторах - они специально предназначены для этого персонала (логика в профессиональном коде должна быть делегирована в файл services.py, по крайней мере). Но давайте для простоты оставим логику в сериализаторе.
class ClubSerializer(serializers.ModelSerializer):
address = AddressSerializer()
class Meta:
model = Club
fields = ['id', 'name', 'address']
def create(self, validated_data):
address_data = validated_data.pop("address")
instance = super().create(validated_data)
instance.address = Address.objects.create(club=instance, **address_data)
return instance
Вид действия
@action(detail=False,methods=['post'])
def register(self, request):
serializer = ClubSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)