#python #django #django-rest-framework #django-filter
#python #django #django-rest-framework #django-фильтр
Вопрос:
serializers.py
from rest_framework import serializers
from .models import Flight, Segment, Airport
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
fields = self.context['request'].query_params.get('fields')
if fields:
fields = fields.split(',')
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields.keys())
for field_name in existing - allowed:
self.fields.pop(field_name)
class SegmentSerializer(serializers.ModelSerializer):
class Meta:
model = Segment
fields = ( # TODO - Could be __all__ if no fine tuning
'id', 'flight_id', 'dep_code', ...
)
class FlightSerializer(DynamicFieldsModelSerializer, serializers.ModelSerializer):
segments = SegmentSerializer(many=True, source='segment_set')
class Meta:
model = Flight
fields = ( # TODO - Could be __all__ if no fine tuning
'id', 'dep_air', 'dest_air', ...
)
class AirportSerializer(DynamicFieldsModelSerializer, serializers.ModelSerializer):
dep_air = FlightSerializer(many=False, source='dep_air_airport')
class Meta:
model = Airport
fields = ('iata_code', 'name', 'continent', 'iso_country',)
При запуске сервера я получаю следующую ошибку:
File "/Users/me/PycharmProjects/fly_baby/flight_data/serializers.py", line 55, in AirportSerializer
dep_air = FlightSerializer(many=False, source='dep_air_airport')
File "/Users/me/PycharmProjects/fly_baby/flight_data/serializers.py", line 15, in __init__
fields = self.context['request'].query_params.get('fields')
KeyError: 'request'
Цель состоит в том, чтобы вложить рейсы в аэропорты или наоборот, но это кажется невозможным, когда я использую DynamicFieldsModelSerializer mixin. Инициализация запрашивает self.context[‘запрос’], который не существует для следующей строки
dep_air = FlightSerializer(many=False, source='dep_air_airport')
Я полагаю, что я каким-то образом должен передавать контекст, но я не знаю, как это возможно, учитывая мою перегруженную дженериками настройку.
Дополнительный код::
views.py
class AirportFlightViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = FlightSerializer
def get_queryset(self):
return Flight.objects.filter(flight=self.kwargs['airport_pk'])
urls.py
router = DefaultRouter()
router.register(r'flights', views.FlightViewSet)
router.register(r'segments', views.SegmentViewSet)
router.register(r'airports', views.AirportViewSet)
flights_router = routers.NestedSimpleRouter(router, r'flights', lookup='flight')
flights_router.register(r'segments', views.FlightSegmentViewSet, basename='flight-segments')
airports_router = routers.NestedSimpleRouter(router, r'airports', lookup='airport')
airports_router.register(r'flights', views.AirportFlightViewSet, basename='airport-flights')
urlpatterns = [
path('', views.index),
path('api/', include(router.urls)),
path('api/', include(flights_router.urls)),
path('api/', include(airports_router.urls)),
]
Ответ №1:
Вы можете редактировать DynamicFieldsModelSerializer
, чтобы не зависеть от присутствующего контекста, чтобы его можно было создать без него, используя .get()
:
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
request = self.context.get('request')
if request:
fields = request.query_params.get('fields')
if fields:
... # code as before
Однако обратите внимание, что при таком использовании дочерний сериализатор ( FlightSerializer
в данном случае) всегда будет иметь все примененные поля. Однако это имеет смысл, поскольку при запросе airport вы ожидаете fields
, что параметр повлияет на поля аэропорта, а не на рейсы.