Django Rest Framework - URL с параметрами запроса в сериализаторе - PullRequest
0 голосов
/ 12 июля 2020

У меня есть модели Story и Post, где Post принадлежит Story. Я хочу, чтобы URL-адрес получал все сообщения, связанные с данной историей.

Мне удалось переопределить get_queryset моего PostViewSet, чтобы фильтровать сообщения по истории с URL-адресами, такими как http://localhost:8000/posts/?story=1/. Это прекрасно работает, если я ввожу URL напрямую. Теперь я хочу вернуть такой URL-адрес в моем StorySerializer. Я хотел бы иметь возможность получать ответы на истории, которые выглядят следующим образом:

[
    {
        "url": "http://localhost:8000/stories/1/",
        "title": "Hero's Journey",
        "openings": 0,
        "date_created": "2020-06-28T16:53:35.150630Z",
        "posts": "http://localhost:8000/posts/?story=1/"
    },
    {
        "url": "http://localhost:8000/stories/2/",
        "title": "Halo 3",
        "openings": 0,
        "date_created": "2020-06-28T18:17:12.973586Z",
        "posts": "http://localhost:8000/posts/?story=2/"
    }
]

Есть ли поддержка DRF для такого рода вещей? Я пытался использовать HyperlinkedIdentityField с 'post-list' View в моем StorySerializer, но не смог найти комбинацию параметров, которая бы работала. Текущее исключение, которое я получаю: AttributeError: 'Story' object has no attribute 'posts'

Сериализаторы

class StorySerializer(serializers.HyperlinkedModelSerializer):
    posts = serializers.HyperlinkedIdentityField(
        view_name = 'post-list',
        many=True,
        lookup_field = 'pk',
        lookup_url_kwarg = 'story',
    )
    class Meta:
        model = models.Story
        fields = ['url', 'title', 'openings', 'date_created', 'posts']


class PostSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.Post
        fields = ['url', 'story', 'user', 'text', 'date_created']

Просмотры

class StoryViewSet(viewsets.ModelViewSet):
    queryset = models.Story.objects.all()
    serializer_class = serializers.StorySerializer


class PostViewSet(viewsets.ModelViewSet):
    queryset = models.Post.objects.all()
    serializer_class = serializers.PostSerializer

    def get_queryset(self):
        queryset = self.queryset
        story_id = self.request.query_params.get('story', None)
        if story_id is not None:
            queryset = queryset.filter(story=story_id)
        return queryset

Модели

class Story(models.Model):
    title = models.CharField(max_length=100)
    date_created = models.DateTimeField(default=timezone.now)
    openings = models.PositiveSmallIntegerField(default=0)
    participant = models.ManyToManyField(User)


class Post(models.Model):
    text = models.CharField(max_length=300)
    user = models.ForeignKey(
        User,
        on_delete=models.PROTECT)
    story = models.ForeignKey(
        Story,
        on_delete=models.PROTECT)
    date_created = models.DateTimeField(default=timezone.now)

1 Ответ

0 голосов
/ 16 июля 2020

Я смог найти здесь отличное решение, переопределив метод get_url для прямого сопоставления значения pk с историей. { ссылка }

from rest_framework.reverse import reverse
import urllib

class StoryPostsHyperlinkedIdentityField(serializers.HyperlinkedIdentityField):
    def get_url(self, obj, view_name, request, format):
        lookup_field_value = getattr(obj, self.lookup_field, None)
        result = '{}?{}'.format(
            reverse(view_name, kwargs={}, request=request, format=format),
            urllib.parse.urlencode({'story': lookup_field_value})
        )
        return result


class StorySerializer(serializers.HyperlinkedModelSerializer):
    posts = StoryPostsHyperlinkedIdentityField(
        view_name='post-list',
    )
    class Meta:
        model = models.Story
        fields = ['url', 'title', 'openings', 'date_created', 'posts']
...