2016-05-17 3 views
7

Это довольно стандартная задача в Django REST Framework для добавления дополнительных args/kwargs в сериализатор для установки значений полей, заданных не через request.data, а через значение в параметрах url или куки. Например, мне нужно установить поле user моей модели комментариев, равное request.user по запросу POST. Эти дополнительные аргументы называются контекстом.Django REST Framework: как работает сериализатор?

Несколько вопросов (1, 2) на StackOverflow предположить, что я переопределить get_serializer_context() метод моего ModelViewSet. Я сделал, и это не помогает. Я попытался понять, что случилось, и выяснил, что я не понимаю из исходного кода, как эта контекстная система должна работать в целом. (документации по этому вопросу также не хватает)

Может ли кто-нибудь объяснить, где сериализатор добавляет контекст в обычные данные запроса? Я нашел два места, где он сохраняет значения из контекста.

  1. serializer.save(), метод, который смешивает kwargs с использованием проверенных данных, но это, как правило, вызывается без аргументов (например, путем ModelMixins).
  2. fields.__new__(), который кэширует аргументы и kwargs, но кажется, что никто их не читает позже.

ответ

7

Всякий раз, когда вы используете общие взгляды или viewsets, DRF (3.3.2) добавляет request объекта, view объекта и format к сериализатору context. Вы можете использовать serializer.context для доступа, скажем request.user в сериализаторе.

Это добавляется, когда вызывается get_serializer_class(). Внутри этого метода он вызывает метод get_serializer_context(), где все эти параметры добавляются в его контекст.

DRF исходный код для справки:

class GenericAPIView(views.APIView): 
    """ 
    Base class for all other generic views. 
    """ 

    def get_serializer(self, *args, **kwargs): 
     """ 
     Return the serializer instance that should be used for validating and 
     deserializing input, and for serializing output. 
     """ 
     serializer_class = self.get_serializer_class() 
     kwargs['context'] = self.get_serializer_context() 
     return serializer_class(*args, **kwargs)  

    def get_serializer_context(self): 
     """ 
     Extra context provided to the serializer class. 
     """ 
     return { 
      'request': self.request, 
      'format': self.format_kwarg, 
      'view': self 
     } 
+0

То, что я понял, но что будет дальше? Я не вижу, где Serializer использует этот контекст, чтобы заполнить поля значениями, взятыми из него. –

+0

В нормальных случаях контекст не будет использоваться сериализатором. Если мы хотим получить доступ к объекту 'request' в сериализаторе, мы будем использовать' self.context.get ('request') '. Кроме того, в любом методе 'to_representation' поля сериализатора мы можем получить доступ к' context', используя переменную 'self.context'. –

+0

(Из [docs] (http://www.django-rest-framework.org/api-guide/serializers/#including-extra-context)). Одним из распространенных случаев включения контекста является то, что вы используете сериализатор, который включает в себя гиперссылки, что требует, чтобы сериализатор имел доступ к текущему запросу, чтобы он мог правильно генерировать полные URL-адреса. –

0

установить значения полей устанавливаются не через request.data, но через значения в параметрах URL-адрес или печенье. Например, мне нужно установить поле пользователя моей модели комментариев равным request.user по запросу POST.

Это, как я обрабатывать оба случая в моей ModelViewSet:

def perform_create(self, serializer): 

    # Get article id from url e.g. http://myhost/article/1/comments/ 
    # obviously assumes urls.py is setup right etc etc 
    article_pk = self.kwargs['article_pk'] 
    article = get_object_or_404(Article.objects.all(), pk=article_pk) 

    # Get user from request 
    serializer.save(author=self.request.user, article=article) 

К сожалению, вложенные объекты не является стандартом для ФПИ, но это, кроме точки. :)

Смежные вопросы