#detail_route does not work pagination in django rest framework - django

Can I use #detail_router's pagination?
class GroupViewSet(viewsets.ReadOnlyModelViewSet):
"""
Group View Set
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
pagination_class = StandardResultsSetPagination
#detail_route()
def user(self, request, pk=None):
_group = self.get_object()
users_post = _group.user_set.all()
page = self.paginate_queryset(users_post)
if page is not None:
serializers = UserSerializer(users_post, many=True, context={'request': request})
return self.get_paginated_response(serializers.data)
serializers = UserSerializer(users_post, many=True, context={'request': request})
return Response(serializers.data)
Pagination does not work well in Djagno Rest Framework.
It only works page size. One page has whole contents, and next page is same whole contents.
How can I do for pagination?

Instead of using users_post in your UserSerializer you'll need to use page:
if page is not None:
serializers = UserSerializer(page, many=True, context={'request': request})
Edit:
Note that it should be serializer and not serializers as you only have one serializer.

Related

Supporting search queries in Django Rest Framework

Im currently trying to allow users to search my database from the client side and return the response to them. I'm a little confused on where in the view I need to support the search query, or if the way I'm going about it is even correct. I've done some research already and found out about the SearchFilter from DRF but unsure how to incorporate it into my code.
Here is my views for the resource i'm trying to search:
class Recipes(ViewSet):
def list(self, request):
recipes = Recipe.objects.all()
user = self.request.query_params.get('user', None)
if user is not None:
recipes = recipes.filter(author = user)
serializer = RecipeSerializer(recipes, many=True, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
recipe = Recipe.objects.get(pk=pk)
serializer = RecipeSerializer(recipe, context={'request': request})
return Response(serializer.data)
except Exception as ex:
return HttpResponseServerError(ex)
Based on my research I've found that I can use:
serializer_class = RecipeSerializer
queryset = Recipe.objects.all()
filter_backends = (SearchFilter,)
filter_fields = ('title', 'ingredients')
in some way but i'm not exactly sure how. Any guidance is appreciated

Broken images in Django

I have a problem with my images, which started when I changed a part of my code in view.p (API)
from:
class PostListView(ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
to:
#api_view(['GET'])
def PostListView(request, *args, **kwargs):
queryset = Post.objects.all()
username = request.GET.get('username')
if username != None:
queryset = queryset.filter(author__username__iexact=username)
serializer = PostSerializer(queryset, many=True)
return Response(serializer.data, status=200)
I did this because I wanted to pass "username" into it and I dont know how to do that using APIView, so i used this, but then my images are broken and i notice with the APIView, the images url starts from "127.0.0.1/8000/..." but with this new view the url is "localhost/...." which i think is the problem.
How do i go about it please
Pass request to PostSerializer's context
For ex:
serializer = PostSerializer(queryset, many=True, context = {'request':request})

Adding Filter to Django REST API

I am pretty new to Django and REST and I want to be able to specify a value and have the REST api only return a row where that value is met. Kinda like in sql select * from exampleTBL where id = 1 and then the first row is returned. But it would be done through the url: www.website/api/tmpHost/?id=1 and t hen the first row is returned through the REST API
My view looks like:
class tmp_HostList(APIView):
def get (self, request, format=None):
tmp_hosts = tmp_Host.objects.all()
serializer = tmp_HostSerializer(tmp_hosts, many=True, context={'request': request})
return Response(serializer.data)
def post(self, request, format=None):
serializer = tmp_HostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
my url looks like:
url(r'^api/tmpHost/$', views.tmp_HostList.as_view()),
my serializer looks like:
class tmp_HostSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
class Meta:
model = tmp_Host
fields = '__all__'
How would I go about doing this? I've seen solutions around here but they don't seem to work for me. The differences where that I use APIView and my serializer line would be: serializer = tmp_HostSerializer(tmp_hosts, many=True, context={'request': request}) while theirs would be simple like: serializer = tmp_HostSerializer
The simplest way is just check for get parameters and return a filtered object by the parameter:
from django.shortcuts import get_object_or_404
class tmp_HostList(APIView):
def get (self, request, format=None):
param = request.GET.get('id')
if param:
tmp_host = get_object_or_404(Host, id=param)
serializer = tmp_HostSerializer(tmp_host)
else:
tmp_hosts = tmp_Host.objects.all()
serializer = tmp_HostSerializer(tmp_hosts, many=True)
return Response(serializer.data)
There is also built in filtering for generic views and viewsets doc link
But the best choice is create a separate view for detail page or use viewset/generic views.
So your view is stay the same and you add a new one for detail page.
urls:
url(r'^api/tmpHost/(?P<id>\d+)$', views.tmp_HostList.as_view())
views:
class tmp_HostDetail(APIView):
def get (self, request, id=None, format=None):
tmp_host = get_object_or_404(Host, id=id)
serializer = tmp_HostSerializer(tmp_host)
return Response(serializer.data)

How to apply a djngoFilterBackend in a detail_route() viewset

I want to use django filters in a view which has some other behaviour, without returning viewset retrieve or list methods.
My code is the following:
class ArticleView(ReadOnlyModelViewSet):
serializer_class = get_serializer_class(Article)
queryset = Article.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('TYPE',)
#detail_route()
def articles(self, request, pk=None):
some_behaviour()
return MY QUERYSET (which can or cannot be modified) FILTERED
so by hitting /api/articles and its derivates the queryset gets filtered correctly, also if i return self.retrieve(request) (obviously), but i am not able to modify my queryset. Then my question is, what is needed to apply django filters EXPLICITLY in that situation, or how can i tell him to do that instead of doing request.query_string.pop(bla bla bla).
Thanks!
I've recently got similar problem.
I've found ViewSet.filter_queryset() function that is doing exactly that.
Remember that ViewSet.get_object() also use self.filer_queryset() so make Your detailed_route method usinq get_object_by_pk() like:
class ViewSet:
def get_object_by_pk(self, pk):
return self.get_queryset().get(pk=pk)
#detail_route():
def something(self, request, pk):
object = self.get_object_by_pk(pk)
queryset = object.whatevet_set
page = self.paginate_queryset(self.filter_queryset(queryset))
if page is not None:
serializer = SerializerClass(page, many=True, context={'request': request})
return self.get_paginated_response(serializer.data)
serializer = SerializerClass(queryset, many=True, context={'request': request})
return Response(serializer.data)

Django rest framework - self.context doesn't have request attribute

class MyModelSerializer(serializers.ModelSerializer):
field1 = serializers.CharField()
field2 = serializers.SerializerMethodField('get_awesome_user')
def get_current_user(self):
request = self.context.get("request")
if request and hasattr(request, "user"):
return request.user
return None
def get_awesome_user(self, obj):
user = self.get_current_user()
## use this user object, do some stuff and return the value
return ...
My api(which uses authentication_classes and permission_classes) is using this serializer and the get_current_user function always returns None. when I debug it, I found that self.context is empty dictionary, i.e {}. to be double sure I also printed self.context.keys(), still it's empty list.
I followed this thread.
Get current user in Model Serializer
PS: I'm using djangorestframework==3.3.3, Django==1.9.1
EDIT: adding viewset code
class MyModelViewSet(viewsets.ModelViewSet):
authentication_classes = (SessionAuthentication, BasicAuthentication, TokenAuthentication)
permission_classes = (IsAuthenticated,)
def list(self, *args, **kwargs):
queryset = MyModel.objects.all()
page = self.paginate_queryset(queryset)
if page is not None:
serializer = MyModelSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = MyModelSerializer(queryset, many=True)
return Response(serializer.data)
How do you create serializer in your viewset's list() method? You should call
serializer = self.get_serializer(data=request.data)
to get your serializer context filled automatically as it is done in default implementation of this method in DRF mixins., but I have a feeling that you're just creating it manually, like this:
serializer = MyModelSerializer(instance)
So, to fix this, you should either call get_serializer(), or pass extra context argument to serializer constructor:
serializer = MyModelSerializer(instance, context={'request': request, ...})