2013-10-19 12 views
12

Geçerli isteği yapan kullanıcıya özel bilgiler içeren bir seri hale getirici alanına bir alan eklemek istiyorum (Bunun için ayrı bir son nokta oluşturmak istemiyorum). İşte bunu yolu yaptılar edilir:Kullanıcıya özel alanları Django REST Framework serializer'a ekle

viewset:

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 

serileştirici:

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 

sevdim makalelerin önceden getirilmesini enjekte etmek daha iyi bir yer var mı ya Genel olarak bunu yapmak için daha güzel bir yol?

cevap

8

Like model nesnesinde olabildiğince fazla bunları denemeye ve daha sonra özel bir seri hale getirici alanına atma eğiliminde olmalıyım.

serileştirici tarla sen onların ana seri hale gelen miras context parametresi yoluyla request erişebilirler.

Yani böyle bir şey olabilir:

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 sınıf yöntemi ardından önalımı (ve önbelleğe alma) mantığını olabilir.

Umarım bu yardımcı olur.

+0

Yaptığın tek bir makale geçmek ise user_likes_article' önbelleğe alma/ön yüklemesi yolunda çok yapmak mümkün olmaz 'özel bir alan gibi ama. 'Get_queryset' içinde önceden alma nedenim, isteğiyle ilgili tüm makale kimlikleri orada biliniyor olmasıdır. Sorgulayıcı alanında bir şekilde küme var mı? –

+0

Tek bir makale parametresini kullanarak, (önbelleğe alınmış) user_likes koleksiyonundan (veya benzeri) oluşan bir makaleyi seçmek için kullanacağınızı farzediyorum. QuerySet sadece Articles.objects.all() dır? Orada belirli bir istek yok ama tam olarak nasıl user_likes_article uygulamasının (tabii ki) tam olarak ne yapmaya çalıştığınıza bağlı olduğunu uygularsınız. –

+0

Orijinal sorumumda ciddi bir hata olduğunu fark ettim; Bu, hiçbir şekilde, queryset filtrelemesine ya da sayfalamalarına uymuyordu. Şimdi değiştirdim ve bence biraz daha mantıklı. Ön yükleme işleminin, istekle (filtreleme ve sayfalama) sıkıca nasıl birleştirildiğini ve bunu Like modeline kolayca taşıyamadığımı görebilirsiniz. –

26

Eğer SerializerMethodField

Örnek ile yapabilirsiniz:

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 

o zaman böyle görünümden seri hale çağırmalıdır:

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

Filtreyi kullanırken 'try dışında 'seçeneğine ihtiyacınız yoktur, sorgu boşsa bir hata vermez, boş bir sorguyu döndürür. ve 'count()' yerine, 'exists()' i doğrudan kullanabilirsiniz. – Sassan

0

Django Documentation - SerializerMethodField göre, ben zorunda Hızlı2share kodunu biraz değiştirin.

class ResourceSerializer(serializers.ModelSerializer): 
    liked_by_user = serializers.SerializerMethodField() 

    def get_liked_by_user(self, obj : Resource): 
     request = self.context.get('request') 
     return request is not None and obj.likes.filter(user=request.user).exists() 
İlgili konular