Jak poprawnie kontrolować listę zwracanych pól?

0

Czasami nie potrzebuję pobierać całych obiektów a jedynie "nagłówki" w postaci id i nazwy.
Na przykład jeśli chce wyświetlić listę obiektów w SELECT
Nie jestem do końca pewny jak powinno się to rozwiązać.

http://127.0.0.1:8000/people/
http://127.0.0.1:8000/people/?id_name_only

  1. W rozwiązaniu pierwszym wszystko wydaje się być poprawne ale tworzę dodatkowy serializer, a nie do końca widzi mi się tworzenie oddzielnego selializera dla każdego przypadku jaki będzie mi potrzebny

    class MiniPersonSerializer(serializers.ModelSerializer):
        class Meta:
            model = Person
            fields = ('id', 'name',)
    
    
    class PersonSerializer(serializers.ModelSerializer):
        class Meta:
            model = Person
            fields = ('id', 'name', 'surname', 'email', 'age', 'city', 'street', 'zipcode', 'nationality')
    
    
    class PeopleViewSet(viewsets.ModelViewSet):
        queryset = Person.objects.all()
        serializer_class = PersonSerializer
    
        def get_serializer_class(self):
            if self.request.query_params.__contains__('id_name_only'):
                return MiniPersonSerializer
            return PersonSerializer
  1. Chciałbym znaleźć rozwiązanie tego typu, nie umiem tyko nadpisać pola fields w Meta Klasie Serializera i też nie jestem pewny czy powinno się tak robić.

    class PersonSerializer(serializers.ModelSerializer):
        class Meta:
            model = Person
            fields = ('id', 'name', 'surname', 'email', 'age', 'city', 'street', 'zipcode', 'nationality')
    
        def __init__(self, *args, **kwargs):
            super(PersonSerializer, self).__init__(*args, **kwargs)
            if self.context.get('info_to_serializer') == 'id_name_only':
                self.Meta.fields = ('id', 'name',)  #  TO NIESTETY NIE DZIAŁA
    
    
    class PeopleViewSet(viewsets.ModelViewSet):
        queryset = Person.objects.all()
        serializer_class = PersonSerializer
    
        def get_serializer_context(self):
            if self.request.query_params.__contains__('id_name_only'):
                return {"info_to_serializer": 'id_name_only'}

  1. Podejście trzecie działa ale jest trochę od d.... strony.
    Wolę usunąć pola których akurat nie potrzebuję bo w większości przypadków zamierzam wykorzystywać większość lub wszystkie pola.


    class PersonSerializer(serializers.ModelSerializer):
        class Meta:
            model = Person
            fields = ('id', 'name')
    
        def __init__(self, *args, **kwargs):
            super(PersonSerializer, self).__init__(*args, **kwargs)
            if self.context.get('info_to_serializer') != 'id_name_only':
                self.Meta.fields = (*self.Meta.fields, 'surname', 'email', 'age', 'city', 'street', 'zipcode', 'nationality')
    
    class PeopleViewSet(viewsets.ModelViewSet):
        queryset = Person.objects.all()
        serializer_class = PersonSerializer
    
        def get_serializer_context(self):
            if self.request.query_params.__contains__('id_name_only'):
                return {"info_to_serializer": 'id_name_only'}

  1. Można również wykorzystać django-restql
    https://github.com/yezyilomo/django-restql

Proszę o poradę jak najlepiej podejść do tego zagadnienia?

2

Wydaje mi się, że nie ma sensu pisać serializera dla każdego przypadku. Wystarczyłoby użycie serializera, który pozwoli na dynamiczne wybranie pól które powinny zostać zwrócone używając argumentu, np: http://127.0.0.1:8000/people/?fields=id,name

Szybkie przeszukanie google zwraca nam: https://stackoverflow.com/questions/23643204/django-rest-framework-dynamically-return-subset-of-fields

1
  1. fajne, proste i poprawne rozwiązanie (do prostych przypadków), jedyne co bym zmienił to self.request.query_params.__contains__('id_name_only'): na 'id_name_only' in self.request.query_params

2 i 3. przekombinowane. czemu po prostu nie nadpiszesz metody .get_fields() na serializerze? w kontekście masz dostęp do requesta (nie polecam) albo po prostu wstrzyknij przez konstruktor pola, które chcesz zwrócić (polecam, mniejszy coupling z request-response lifecycle)

  1. to chyba najlepsze rozwiązanie z proponowanych - użyć gotowca. od siebie dodam jeszcze https://github.com/AltSchool/dynamic-rest i https://github.com/rsinger86/drf-flex-fields

a najlepiej to nie bawić się w przedwczesną optymalizację

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