Вложенные сериализаторы создают метод для каждого сериализатора

У меня есть клубная модель, а также адресная модель.

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)
  1. Но из того, что я читал, следует, что не идеально делать логику в представлениях, а в сериализаторах. Поэтому я могу перенести метод create из create моего представления в create сериализатора. Но что мне не понятно, так это то, что я не могу вызвать метод create вложенных сериализаторов. На самом деле я даже не могу получить объекты вложенного сериализатора, чтобы вызвать его метод create. Вы можете думать об этом так, как будто вы обходите дерево и вызываете методы create каждого сериализатора, и если у них есть create, то они вызывают его дочерний объект.

В идеале я не должен реализовывать всю логику в методе create сериализатора ClubRegistrationSerializer. Каждый сериализатор должен отвечать за свою собственную.

Я должен иметь возможность вызвать метод create сериализатора ClubRegistrationSerializer, который должен вызвать метод create сериализаторов Address и Club.

В каждом примере, который я вижу, вся логика обрабатывается в create родительского сериализатора.

  1. Во-вторых, как я могу вызвать 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)
Вернуться на верх