2013-10-19 2 views
12

현재 요청을 작성하는 사용자에 대한 정보가 들어있는 serializer에 필드를 추가하고 싶습니다.이 필드는 별도의 끝점을 만들지는 않습니다. 여기에 내가 길을했던된다Django REST Framework serializer에 사용자 특정 필드를 추가하십시오.

뷰셋 :

class ArticleViewSet(viewsets.ModelViewSet): 
    queryset = Article.objects.all() 
    serializer_class = ArticleSerializer 
    filter_class = ArticleFilterSet 

    def prefetch_likes(self, ids): 
     self.current_user_likes = dict([(like.article_id, like.pk) for like in Like.objects.filter(user=self.request.user, article_id__in=ids)]) 

    def get_object(self, queryset=None): 
     article = super(ArticleViewSet, self).get_object(queryset) 
     self.prefetch_likes([article.pk]) 
     return article 

    def paginate_queryset(self, queryset, page_size=None): 
     page = super(ArticleViewSet, self).paginate_queryset(queryset, page_size) 
     if page is None: 
      return None 

     ids = [article.pk for article in page.object_list] 
     self.prefetch_likes(ids) 

     return page 

시리얼 라이저 :

class ArticleSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Article 

    def to_native(self, obj): 
     ret = super(ArticleSerializer, self).to_native(obj) 

     if obj: 
      view = self.context['view'] 
      ret['has_liked'] = False 
      if hasattr(view, 'current_user_liked'): 
       ret['has_liked'] = obj.pk in view.current_user_liked 

     return ret 

좋아하는 기사의 프리 페치를 주입 할 수있는 더 좋은 곳이 있는가 또는 일반적으로이 작업을 수행하는 더 좋은 방법입니까?

답변

8

나는 Like 모델 개체에 가능한 한 많은 것을 넣고 나머지는 사용자 지정 serializer 필드에 넣으려고합니다.

는 시리얼 필드에서 당신은 그들의 부모 시리얼에서을 상속 context 매개 변수를 통해 request에 액세스 할 수 있습니다.

그래서 당신은 같은 것을 할 수 있습니다

class LikedByUserField(Field): 
    def to_native(self, article): 
     request = self.context.get('request', None) 
     return Like.user_likes_article(request.user, article) 

user_likes_article 클래스 방법은 다음 프리 페치 (캐싱) 로직을 캡슐화 할 수있다.

도움이 되었기를 바랍니다.

+0

나는 custom_field를 좋아하지만'user_likes_article'은 캐싱/프리 페치의 방식으로 할 일이 많지 않다. 'get_queryset' 내부에서 프리 페치 (prefetching)를 한 이유는 요청과 관련된 모든 기사 ID가 그곳에 알려져 있기 때문입니다. serializer 필드에서 쿼리 세트를 사용할 수 있습니까? –

+0

나는 당신이 user_likes의 (캐시 된) 콜렉션에서 기사를 선택하기 위해 단일 기사 매개 변수를 사용한다고 가정한다. QuerySet은 단지 Articles.objects.all() 일 뿐인가? 거기에는 특별한 요구가 없지만 정확하게 당신이하려는 일에 따라 user_likes_article을 어떻게 구현하는지 정확하게 알 수 있습니다. –

+0

나는 원래의 질문에 심각한 버그가 있음을 깨달았습니다. queryset 필터링이나 페이지 매김을 전혀 고려하지 않았습니다. 나는 그것을 지금 수정했고, 나는 그것이 조금 더 의미가 있다고 생각한다. 프리 페치가 요청 (필터링 및 페이지 매김)과 어떻게 밀접하게 결합되어 있는지, Like 모델로 쉽게 이동할 수 없는지를 알 수 있습니다. –

26

당신이 SerializerMethodField

예와 함께 할 수 있습니다

class PostSerializer(serializers.ModelSerializer): 
    fav = serializers.SerializerMethodField('likedByUser') 

    def likedByUser(self, obj): 
     request = self.context.get('request', None) 
     if request is not None: 
      try: 
       liked=Favorite.objects.filter(user=request.user, post=obj.id).count() 
       return liked == 1 
      except Favorite.DoesNotExist: 
       return False 
     return "error" 

    class Meta: 
     model = Post 

는 다음과 같이보기에서 시리얼을 호출해야합니다 :

class PostView(APIVIEW): 
    def get(self,request): 
     serializers = PostSerializer(PostObjects,context={'request':request}) 
+0

필터를 사용할 때'try except'가 필요하지 않습니다. 쿼리가 비어 있으면 오류가 발생하지 않고 단순히 빈 쿼리를 반환합니다. 'count()'대신'exists()'를 직접 사용할 수 있습니다. – Sassan

관련 문제