Django Rest Framework - zagnieżdżone serializowanie danych

0

Cześć,
tym razem mam dość obszerne pytanie.
Testuję sobie DRF, korzystam z dokumentacji. DRF - nested serializers
No i na ogół chcę zbudować Api, które będzie przyjmować taką postać danych (dokładnie jak w dokumentacji DRF):

data = {
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}

Gdy używam Django ORM i Queryset - działa, mam możliwość wpisania kolejnych rekordów do bazy danych. Jednak gdy próbuję użyć:

r = requests.post(
    'http://127.0.0.1:8000/api/album/',
    data=data,
)

niestety zawsze odpowiedź HTTP 400.

Kolejno models.py:

class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=100)

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    duration = models.IntegerField()

    class Meta:
        unique_together = ['album', 'order']
        ordering = ['order']

    def __str__(self):
        return '%d: %s' % (self.order, self.title)

serializers.py

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ['order', 'title', 'duration']

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)

    class Meta:
        model = Album
        fields = ['album_name', 'artist', 'tracks']

    def create(self, validated_data):
        tracks_data = validated_data.pop('tracks')
        album = Album.objects.create(**validated_data)
        for track_data in tracks_data:
            Track.objects.create(album=album, **track_data)
        return album

views.py

class TrackViewSet(viewsets.ModelViewSet):
    serializer_class = TrackSerializer
    queryset = Track.objects.all()

class AlbumViewSet(viewsets.ModelViewSet):
    serializer_class = AlbumSerializer
    queryset = Album.objects.all()

Czy w takim razie, powinienem skupić się na budowie odpowiedniej obsługi takiego zapytania w AlbumViewSet?

1

@CzakuGim:

  1. Gdy używam Django ORM i Queryset - działa, mam możliwość wpisania kolejnych rekordów do bazy danych.
    Oczywiscie bo w ten sposób całkowicie pomijasz serializer, i nie odzwierciedla to jak jest przetwarzany request.

  2. Trochę mało danych podałeś, co zwraca na response kiedy dostajesz 400, ale:

r = requests.post(
    'http://127.0.0.1:8000/api/album/',
    data=data,
)

A to leci JSONem w ogóle?:P Użyj postmana/insomnii do tego. Jeśli to fragment twoich testów to skorzystałbym z wbudowanego APIClient z rest_framework.test, o tak (albo uzyj json.dumps(data) lub json=data i zobacz czy zaskoczy) :

client = ApiClient()
client.post(url, data=data, format='json')
  1. return '%d: %s' % (self.order, self.title) - użyj f-stringa a nie tego starocia :)

  2. /api/album/' - powinno być albums

0
  1. Pomogło ;)
  2. Oczywista sprawa, fragment skopiowany z dokumentacji DRF - nie edytowałem :)
  3. Ooo tak, często o tym zapominam, dzięki :)

Co do rozwiązania po prostu zamiast data wrzucam json = data

data = {
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}
r = requests.post(
    'http://127.0.0.1:8000/api/album/',
    data=data,
)

Dziękuję za wszelką pomoc!

1 użytkowników online, w tym zalogowanych: 0, gości: 1