I am trying to create an endpoint that returns a list of posts. I want lets say 2 posts per page (for testing only! I know its not that big of a number to cause problem!).
here is my
views.py
class blogsViewSet(ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostSerializer
pagination_class = pagination.CustomPagination
def list(self, request):
data = request.data
uid = data['uid']
context = {"user": uid}
blogs = Posts.objects.all()
serializer = PostSerializer(blogs, many= True, context= context)
return Response(serializer.data)
here is my
serializers.py
class PostSerializer(ModelSerializer):
isLiked = serializers.SerializerMethodField(method_name='check_react')
totalLikes = serializers.SerializerMethodField(method_name='get_likes')
totalComments = serializers.SerializerMethodField(method_name='get_comments')
def check_react(self, post):
userObj = Users.objects.get(userID = self.context['user'])
#print(type(userObj))
if Likes.objects.filter(postID = post, userID = userObj).exists():
isLiked = Likes.objects.get(postID = post, userID = userObj)
likeObj = LikeSerializer(isLiked)
#print('isLiked: ', likeObj.data['isLiked'])
return (likeObj.data['isLiked'])
return(False)
#print(isLiked)
def get_likes(self, post):
count = Likes.objects.filter(postID = post).count()
return count
def get_comments(self, post):
count = PostsComments.objects.filter(postID = post).count()
return count
class Meta:
model = Posts
fields = '__all__'
and, here is my
pagination.py,
from rest_framework import pagination
class CustomPagination(pagination.PageNumberPagination):
page_size = 2
page_size_query_param = 'page_size'
max_page_size = 3
page_query_param = 'p'
I am importing this class on views.py and it works as expected when I try to retrieve a list of users via userMVS
class userMVS(ModelViewSet):
queryset = Users.objects.all()
serializer_class = UserSerializer
pagination_class = pagination.CustomPagination
You must write your list function of views as -
def list(self, request, *args, **kwargs):
queryset = Posts.objects.all()
paginatedResult = self.paginate_queryset(queryset)
serializer = self.get_serializer(paginatedResult, many=True)
return Response(serializer.data)
Edits -
Suppose this is my pagination class -
class CustomPagination(PageNumberPagination):
page_size = 8
page_query_param = "pageNumber"
and used in this way at class level and mentioned above at list function -
class blogsViewSet(ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostSerializer
pagination_class = CustomPagination
then this is the url that should work
http://localhost:8000/urlofpostviewset/?pageNumber=passThePageNumber
Do read from the documents all the properties you use at CustomPagination class.
Related
I have a model like this:
class Camper(models.Model):
location = models.PointField()
name = models.CharField(max_length=255)
and a viewset like this:
class CamperViewSet(viewsets.ModelViewSet):
...
def retrieve(self, request, *args, **kwargs):
"""Retrieve a Camper instance."""
show_weather = request.query_params.get('showWeather', False)
instance = self.get_object()
if show_weather:
lat = instance.location.y
lon = instance.location.x
instance.weather = getWeatherFromLatLon(lat, lon)
serializer = self.get_serializer(instance)
return Response(serializer.data)
So when I request /api/campers/8?showWeather=true I make another request in my view to get the weather from the current position.
How do I add it to my serializer ? It's an optional field so I need to manage this and it's only used in /campers/id so it will not be used in list/create/put/etc
My serializer looks like this:
class CamperSerializer(serializers.ModelSerializer):
camper_id = serializers.IntegerField(source='id')
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location')
you can add custom serializer for retrive only todo it. I called CamperRetriveSerializer.
Inside CamperRetriveSerializer, you can use SerializerMethodField for define field not have in database.
And you want check param show_weather from request, best is pass value of it to context and get it in serializer.
Like this:
class CamperRetriveSerializer(serializers.ModelSerializer):
weather = serializers.SerializerMethodField()
camper_id = serializers.IntegerField(source='id')
def get_weather(self, obj):
show_weather = self.context.get('show_weather')
if show_weather:
lat = obj.location.y
lon = obj.location.x
return getWeatherFromLatLon(lat, lon)
# define default value if not show_weather in this
return ''
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location', 'weather')
class CamperViewSet(viewsets.ModelViewSet):
...
def retrieve(self, request, *args, **kwargs):
"""Retrieve a Camper instance."""
instance = self.get_object()
show_weather = self.request.query_params.get('showWeather', False)
context = {
'show_weather': show_weather
}
serializer = CamperRetriveSerializer(instance, context=context)
return Response(serializer.data)
You can use two different serializers for this.
class CamperViewSet(viewsets.ModelViewSet):
serializer_class = CamperSerializer
def get_serializer_class(self):
serializer_class = self.serialzier_class
if self.request.method == 'GET':
serializer_class = CamperSerializerGet
return serializer_class
#Serializer for GET request
class CamperSerializerGet(serializers.ModelSerializer):
weather = serialziers.SerializerMethodField()
camper_id = serializers.IntegerField(source='id')
def get_weather(self, obj):
return obj.weather
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location', 'weather')
#For other requests call this
class CamperSerializer(serializers.ModelSerializer):
camper_id = serializers.IntegerField(source='id')
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location')
I have two fields of type time in postgresql, which saves these values in 24 format (03:30 PM would save 15:30:00).
How can I run a search with a time in format 12 and match it with its equivalent in format 24?
How can I order these fields in 12 format?
the fields are 'ho_inicio' and 'ho_fin'.
My Viewset (I override the list method to search regardless of accents):
class HorasEscolaresViewSet(ListModelPagination, viewsets.ModelViewSet):
queryset = TbledcHora.objects.all()
serializer_class = HorasEscolaresSerializer
filter_backends = [DjangoFilterBackend, AliasedOrderingFilter]
filterset_class = HorasEscolaresFilter
search_fields = ['id_nivel_academico__nb_nivel_academico', 'nu_hora']
filterset_fields = ['id_nivel_academico', 'in_status']
ordering_fields=('id_nivel_academico', 'nu_hora', 'ho_inicio', 'ho_fin')
ordering= 'id_nivel_academico'
renderer_classes = (EmberJSONRenderer, )
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if "search" in request.GET:
if request.GET['search'] != '':
q_list = []
q_list.append(Q(id_nivel_academico__nb_nivel_academico__unaccent__icontains=request.GET['search']))
queryset = queryset.filter(reduce(operator.or_, q_list))
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many = True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
My serializer:
class HorasEscolaresSerializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
ho_inicio = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats)
ho_fin = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats)
class Meta:
model = TbledcHora
fields = '__all__'
depth = 1
Is it someway to filter querysets with multiple optional parameters in Django more efficiently?
For ex. I have product list and user can filter it by using multiple GET params. 6 params in this case. Thanks.
class ProductList(ListAPIView):
permission_classes = (IsAdminUser,)
serializer_class = ProductSerializer
def get_queryset(self):
queryset = Product.objects.order_by('-created_at')
category_id = self.request.GET.get('category_id')
color = self.request.GET.get('color')
size = self.request.GET.get('size')
status = self.request.GET.get('status')
date_from = self.request.GET.get('date_from')
date_to = self.request.GET.get('date_to')
if category_id:
queryset = queryset.filter(category_id=category_id)
if color:
queryset = queryset.filter(color=color)
if size:
queryset = queryset.filter(size=size)
if status:
queryset = queryset.filter(status=sistatusze)
if date_from:
queryset = queryset.filter(created_at__gte=date_from)
if date_to:
queryset = queryset.filter(created_at__lte=date_to)
return queryset
You can make a utility function that will not filter the conditions where the value is None:
def filter_if_not_none(qs, **kwargs):
return qs.filter(**{k: v for k, v in kwargs.items() if v is not None})
then we can use this utility as:
class ProductList(ListAPIView):
permission_classes = (IsAdminUser,)
serializer_class = ProblemSerializer
def get_queryset(self):
queryset = Product.objects.order_by('-created_at')
return filter_qs_if_not_none(
queryset,
category_id=self.request.GET.get('category_id')
color=self.request.GET.get('color')
size=self.request.GET.get('size')
status=self.request.GET.get('status')
created_at__gte=self.request.GET.get('date_from')
created_at__lte=self.request.GET.get('date_to')
)
I want to combine 2 models: City and Country in order to have a filter like this: http://localhost:8000/api/v1/geo/location-search/?name=Santa+Fe
I have a ModelViewSet which return serializer data like this:
class LocationSearchAPI(ModelViewSet):
queryset = City.objects.all().order_by('name')
permission_classes = [AllowAny]
serializer_class = CityListSerializer
filter_backends = (DjangoFilterBackend, SearchFilter)
filter_class = LocationFilter
def get_location_list(self, request):
city_qs = City.objects.all().order_by('name')
country_qs = Country.objects.all().order_by('name')
result_qs = list(chain(country_qs, city_qs))
sorted_list = sorted(result_qs, key=lambda instance: -instance.id)
results = list()
for item in sorted_list:
item_type = item.__class__.__name__.lower()
if isinstance(item, City):
serializer = CityLocaliaztionSrl(item)
if isinstance(item, Country):
serializer = CountryLocaliaztionSrl(item)
results.append({'type': item_type, 'data': serializer.data})
return Response(results, status=200)
and this Filter's not work:
class LocationFilter(FilterSet):
class Meta:
model = City
fields = ('type', 'data__name')
How can I use Django Filters in ModelViewSet which return serializer data, hope your guys help me.
I am trying to modify my get_queryset result
Here is my my filter, view and serializer
view.py
class AccountDetailFilter(filters.FilterSet):
product_key = filters.CharFilter(name='product__product_name')
account_name = filters.AllValuesFilter(name='account__account_key')
service_provider_name = filters.CharFilter(name='product__service_provider__service_provider_name', )
allocation_key = filters.CharFilter(name='account__account_allocation__allocation_key')
class Meta:
model = BillingLine
fields = ('product_key', 'account_name', 'service_provider_name', 'allocation_key')
class AccountDetailList(generics.ListAPIView):
serializer_class = BillingSerializer
filter_backends = (DjangoFilterBackend,)
filter_class = AccountDetailFilter
def get_queryset(self):
now = datetime.datetime.now()
start_date = self.kwargs.get('start_date_time', now)
end_date = self.kwargs.get('end_date_time', now)
serializer = BillingSerializer(data={'start_date': start_date, 'end_date': end_date})
serializer.is_valid(raise_exception=True)
queryset = BillingLine.objects.select_related().filter(start_date__gte=start_date, end_date__lte=end_date)
queryset = queryset.order_by('-id')
print(queryset.count())
return queryset
Serializers.py
class BillingSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
start_date = serializers.DateTimeField()
end_date = serializers.DateTimeField()
account_key = serializers.CharField(source='account_id',required=False)
product_key = serializers.CharField(source='product_id',required=False)
total_amount = serializers.FloatField(required=False)
After retrieving the result(ie get_queryset), I need to modify/add the data in the result . Is there any way to do this .
Also can we get the other field values to serializers from the result queryset. Because the queryset = BillingLine.objects.select_related().filter(start_date__gte=start_date, end_date__lte=end_date) is returning the almost all the data (sepecifally product name which is from products table)
Overriding get_queryset() method would serve your purpose perfectly.
For Example:
in your views.py :
class AccountDetailList(generics.ListAPIView):
serializer_class = BillingSerializer
filter_backends = (DjangoFilterBackend,)
filter_class = AccountDetailFilter
def get_queryset(self):
qs = YourModel.objects.filter(**filter_parameter)
return qs
def list(self):
try:
queryset = self.get_queryset()
serialize_value = YourSerializers(queryset,many=True,context={'request': self.request}).data
#Here in "serialize_value" you can append your data as much as you wish
return_val = {
'modified_serialize_value': serialize_value
}
return Response(return_val, status=status.HTTP_200_OK, content_type='application/json')
except Exception as E:
return Response({'error': str(E)}, status=status.HTTP_408_REQUEST_TIMEOUT, content_type='application/json')
I hope this will help.