Я хотел бы предоставить два разных сериализатора и при этом иметь возможность пользоваться всеми возможностями ModelViewSet
:
- При просмотре списка объектов я бы хотел, чтобы у каждого объекта был URL, который перенаправляет на его детали, а все остальные отношения появляются с использованием
__unicode __
целевой модели;
пример:
{
"url": "http://127.0.0.1:8000/database/gruppi/2/",
"nome": "universitari",
"descrizione": "unitn!",
"creatore": "emilio",
"accesso": "CHI",
"membri": [
"emilio",
"michele",
"luisa",
"ivan",
"saverio"
]
}
- При просмотре деталей объекта я бы хотел использовать
HyperlinkedModelSerializer
пример:
{
"url": "http://127.0.0.1:8000/database/gruppi/2/",
"nome": "universitari",
"descrizione": "unitn!",
"creatore": "http://127.0.0.1:8000/database/utenti/3/",
"accesso": "CHI",
"membri": [
"http://127.0.0.1:8000/database/utenti/3/",
"http://127.0.0.1:8000/database/utenti/4/",
"http://127.0.0.1:8000/database/utenti/5/",
"http://127.0.0.1:8000/database/utenti/6/",
"http://127.0.0.1:8000/database/utenti/7/"
]
}
Мне удалось сделать всю эту работу следующим образом:
serializers.py
# serializer to use when showing a list
class ListaGruppi(serializers.HyperlinkedModelSerializer):
membri = serializers.RelatedField(many = True)
creatore = serializers.RelatedField(many = False)
class Meta:
model = models.Gruppi
# serializer to use when showing the details
class DettaglioGruppi(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Gruppi
views.py
class DualSerializerViewSet(viewsets.ModelViewSet):
"""
ViewSet providing different serializers for list and detail views.
Use list_serializer and detail_serializer to provide them
"""
def list(self, *args, **kwargs):
self.serializer_class = self.list_serializer
return viewsets.ModelViewSet.list(self, *args, **kwargs)
def retrieve(self, *args, **kwargs):
self.serializer_class = self.detail_serializer
return viewsets.ModelViewSet.retrieve(self, *args, **kwargs)
class GruppiViewSet(DualSerializerViewSet):
model = models.Gruppi
list_serializer = serializers.ListaGruppi
detail_serializer = serializers.DettaglioGruppi
# etc.
В основном я определяю, когда пользователь запрашивает представление списка или подробное представление, и изменяю его serializer_class
в соответствии с моими потребностями. Я не очень доволен этим кодом, хотя он выглядит как грязный хак, и, самое главное, что, если два пользователя запросят список и детали одновременно?
Есть ли лучший способ добиться этого с помощью ModelViewSets
или я должен отказаться от использования GenericAPIView
?
РЕДАКТИРОВАТЬ:
Вот как это сделать, используя пользовательскую базу ModelViewSet
:
class MultiSerializerViewSet(viewsets.ModelViewSet):
serializers = {
'default': None,
}
def get_serializer_class(self):
return self.serializers.get(self.action,
self.serializers['default'])
class GruppiViewSet(MultiSerializerViewSet):
model = models.Gruppi
serializers = {
'list': serializers.ListaGruppi,
'detail': serializers.DettaglioGruppi,
# etc.
}
django
serialization
django-rest-framework
Черный медведь
источник
источник
Ответы:
Переопределите свой
get_serializer_class
метод. Этот метод используется в ваших модельных миксинах для получения правильного класса Serializer.Обратите внимание, что есть также
get_serializer
метод, который возвращает экземпляр правильного сериализатораисточник
if hasattr(self, 'action') and self.action == 'list'
pk
запрошенный объект, если действие выполненоretrieve
?Вы можете найти этот миксин полезным, он переопределяет метод get_serializer_class и позволяет вам объявить dict, который отображает действие и класс сериализатора или отступает к обычному поведению.
источник
Этот ответ такой же, как принятый ответ, но я предпочитаю делать таким образом.
Общие взгляды
источник
Что касается предоставления различных сериализаторов, почему никто не собирается использовать подход, который проверяет метод HTTP? Это яснее ИМО и не требует дополнительных проверок.
Кредиты / источник: https://github.com/encode/django-rest-framework/issues/1563#issuecomment-42357718
источник
list
иretrieve
действий, у вас есть проблема, которая используетGET
метод. Вот почему django rest framework ViewSets использует концепцию действий , которая похожа, но немного отличается от соответствующих методов http.На основе ответов @gonz и @ user2734679 я создал этот небольшой пакет python, который предоставляет эту функциональность в виде дочернего класса ModelViewset. Вот как это работает.
источник
Хотя предварительное определение нескольких сериализаторов тем или иным способом представляется наиболее очевидным документированным способом, в FWIW существует альтернативный подход, основанный на другом документированном коде и позволяющий передавать аргументы в сериализатор по мере его создания. Я думаю, что было бы более целесообразно, если бы вам нужно было генерировать логику, основанную на различных факторах, таких как уровни администратора пользователя, вызываемое действие, возможно, даже атрибуты экземпляра.
Первая часть головоломки - это документация по динамическому изменению сериализатора в момент его создания . Эта документация не объясняет, как вызывать этот код из набора или как изменять статус полей «только для чтения» после их инициации, но это не очень сложно.
Вторая часть - метод get_serializer, также задокументирован - (чуть дальше вниз по странице от get_serializer_class в разделе «другие методы»), поэтому на него можно было бы безопасно положиться (а источник очень прост, что, как мы надеемся, означает меньше шансов непреднамеренного побочные эффекты в результате модификации). Проверьте исходный код в GenericAPIView (ModelViewSet - и все остальные встроенные классы представлений, которые, по-видимому, - наследуются от GenericAPIView, который определяет get_serializer.
Соединяя их вместе, вы можете сделать что-то вроде этого:
В файле сериализаторов (для меня base_serializers.py):
Тогда в вашем наборе вы можете сделать что-то вроде этого:
И это должно быть! Использование MyViewSet теперь должно создать экземпляр MyDynamicSerializer с нужными вам аргументами - и, предполагая, что ваш сериализатор наследуется от DynamicFieldsModelSerializer, он должен просто знать, что делать.
Возможно, стоит упомянуть, что это может иметь особый смысл, если вы хотите адаптировать сериализатор другими способами ... например, сделать что-то вроде взятия в списке read_only_exceptions и использовать его в белый список, а не в черный список (что я склонен делать). Я также считаю полезным установить поля равными пустому кортежу, если он не прошел, а затем просто убрать проверку «Нет» ... и я установил определения полей в своих наследующих сериализаторах как « все ». Это означает, что никакие поля, которые не передаются при создании экземпляра сериализатора, не выживают случайно, и мне также не нужно сравнивать вызов сериализатора с определением класса наследующего сериализатора, чтобы узнать, что было включено ... например, в рамках инициализации DynamicFieldsModelSerializer:
NB. Если бы я просто хотел, чтобы два или три класса отображались на разные действия, и / или я не хотел какого-либо специально динамического поведения сериализатора, я вполне мог бы использовать один из подходов, упомянутых здесь другими, но я подумал, что это стоит представить в качестве альтернативы. , особенно учитывая его другое использование.
источник