View all data in limit offset pagination - python

I am using limit offset pagination in an API which is being used in two scenarios.
Where the pagination is needed. So as to show limited data in each page.
The API is being used in another place where I have to show all the datas.
Is there any way in Django limit offset pagination to view all the datas?

Add this method to you view and add all as query parameter to you URL to get all rows.
def paginate_queryset(self, queryset, request, view=None):
if 'all' in request.query_params:
return None
return super().paginate_queryset(queryset, request, view)

This answer is the based on #davit answer. I need to change the method signature (for Django 2.2).
def paginate_queryset(self, queryset):
if 'all' in self.request.query_params:
return None
return super().paginate_queryset(queryset)

Related

ListView with different outputs depending on POST or GET

My app is a db of entries that can be filtered and grouped in lists. Index page should show all entries properly paginated, with no filters, and a search form to filter by entry name and types. Is there a way to do this with one ListView and one template, changing behaviors depending if the page was accessed from index (with GET) or from a search (with POST)? If so, how can I change template page title to "Index" or "Search results" accordingly?
Have you tried using get() and post() methods inside your view? It is exatcly what you need.
class YourView(ListView):
...
def get(self, request):
# unique behaviour for GET
def post(self, request, *args, **kwargs):
# unique behaviour for POST
Check out Django docs.

Redirect and reverse differences in Django

I have a question about what are differences of redirect and reverse. Does it have influence on performance. And someone could me explain the differences between these 3 examples of code? What is the purpose of them and how can I efficiently apply them.
if 'comment' in request.POST:
form = CommentCreationForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.comment_user = request.user
comment.comment_item = Item.objects.get(id=pk)
comment.save()
//1 return redirect('detail-page', pk=item.id)
//2 return redirect(reverse('detail-page', kwargs={'pk': item.id}))
//3 return reverse('detail-page')
(I can not add any argument to the third one that`s the only difference I noticed).
The two are not the same for a number of reasons. The first one is that reverse(…) [Django-doc] returns a string that is a URL to visit that view. redirect(…) [Django-doc] on the other hand returns a HttpResponseRedirect object [Django-doc]. This object can be returned by the view, and will normally trigger the browser to visit the page specified in the HTTP response. redirect(…) has a special parameter permanent=… that will based on the value return a HttpResponseRedirect (if permanent=False which is the default), or HttpResponsePermanentRedirect for permanent=True.
Another difference is that the reverse(…) works with args=… and kwargs=… parameters to fill in the values for the URL patterns. This is different for redirect(…) where one passes the positional and named parameters just as positional and named parameters. This thus means that if you do a reverse('some_view', args=(some_parameter,), kwargs={'name': other_parameter}), you obtain a HTTP response that points to that URL with redirect('some_view', some_parameter, name=other_parameter).
A redirect(…) does not per se works on a view name. Indeed, if you pass a URL to the redirect(…) function, like redirect('/foo/bar/qux/'), it will construct a HttpResponseRedirect that redirects to the URL /foo/bar/qux. This is different for reverse(…) that only constructs URLs based on the name of the view, and its parameters.
Finally redirect(…) also accepts a model object that has a .get_absolute_url() method [Django-doc] will result in a HttpResponseRedirect that redirects to the URL constructed by that .get_absolute_url() method.
Your first (//1) and second (//2) line will thus produce the same result: a HttpResponseRedirect that redirects to the same URL, whereas the last one (//3) will return a string that contains a URL to the detail-page view.
According to https://docs.djangoproject.com/en/3.2/topics/http/shortcuts/#redirect 1 and 2 are equivalent. I would assume 3 doesn't work as it's missing the ?required? product id?

How to use Pagination in a Non-Generic View/Viewset?

Prologue:
I have seen this question arising in more than one posts:
Django Rest Framework - APIView Pagination
Pagination not working in DRF APIView
Django rest framework global pagination parameters not working for ModelViewSet
and can also be applied here:
Combine ListModelMixin with APIView to show pagination
I have composed an example on SO Documentation to unify my answers in the above questions but since the Documentation will get shutdown on August 8 2017, I will follow the suggestion of this widely upvoted and discussed meta answer and transform my example to a self-answered post.
Of course I would be more than happy to see any different approach as well!!
Question:
I want to use a Non Generic View/Viewset (eg: APIView) on a Django Rest Framework project.
As I read on the pagination documentation:
Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular APIView, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the mixins.ListModelMixin and generics.GenericAPIView classes for an example.
Can I still continue using a non generic view/viewset?
How can I implement pagination on it?
We can find a solution without the need to reinvent the wheel:
Let's have a look on how the generics pagination is implemented:
django-rest-framework/rest_framework/generics.py.
That is exactly what we are going to use to our view as well!
Let's assume that we have a global pagination setup like the following in:
settings.py:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.DESIRED_PAGINATION_STYLE',
'PAGE_SIZE': 100
}
In order not to bloat our view/viewset's code, we can create a custom mixin to store our pagination code:
class MyPaginationMixin(object):
#property
def paginator(self):
"""
The paginator instance associated with the view, or `None`.
"""
if not hasattr(self, '_paginator'):
if self.pagination_class is None:
self._paginator = None
else:
self._paginator = self.pagination_class()
return self._paginator
def paginate_queryset(self, queryset):
"""
Return a single page of results, or `None` if pagination
is disabled.
"""
if self.paginator is None:
return None
return self.paginator.paginate_queryset(
queryset, self.request, view=self)
def get_paginated_response(self, data):
"""
Return a paginated style `Response` object for the given
output data.
"""
assert self.paginator is not None
return self.paginator.get_paginated_response(data)
Then on views.py:
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from my_app.mixins import MyPaginationMixin
class MyView(APIView, MyPaginationMixin):
queryset = OurModel.objects.all()
serializer_class = OurModelSerializer
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
# We need to override the get method to insert pagination
def get(self, request):
...
page = self.paginate_queryset(self.queryset)
if page is not None:
serializer = self.serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)
And now we have an APIView with pagination.

Django REST Framework - can't override list in ListAPIView

I am using Django REST Framework to create an endpoint that will produce a PDF document. The PDF document will have information that corresponds to a particular Department. I have two desired functionalities -- to be able to download a PDF document, and to be able to preview the document within the browser.
Since the PDF document changes over time based on data that is added to the app, the document needs to be generated in real time when it is requested. As a first step, I'm trying to have the document be generated in a remote file storage location when the following endpoint is hit by a GET request:
departments/<department_pk>/result/preview
Since my endpoint should only take GET requests, I am using a ListAPIView. I'm trying to override the list method so that my custom document generation logic is executed, but it looks like the method is never called. How can I have some custom document generation logic be inserted into my endpoint, so that it is executed when the endpoint is hit by a GET request?
api/urls.py
url(r'^departments/(?P<department_pk>[0-9]+)/result/preview',
include(result_document_urls.result_document_preview_router.urls,
document_app/urls.py
result_document_preview_router = routers.DefaultRouter()
result_document_preview_router.register(r'^', ResultDocumentDetailView.as_view(),
base_name='Department')
document_app/views.py
class ResultDocumentDetailView(generics.ListAPIView):
queryset = Department.objects.all()
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
def list(self, request, department_pk):
queryset = self.get_queryset()
import ipdb; ipdb.set_trace() # this break point is never hit
department = get_object_or_404(queryset, department_pk=department_pk)
...generate document logic...
return Response(status=status.HTTP_200_OK)
replace list method with below code, I think it will work
class ResultDocumentDetailView(generics.ListAPIView):
queryset = Department.objects.all()
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
import ipdb; ipdb.set_trace() # this break point is never hit
department = get_object_or_404(
queryset, department_pk=kwargs.get('department_pk')
)
...generate document logic...
return Response(status=status.HTTP_200_OK)
for more reference see the overrinding method "list"
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py#L35
In your document_app/urls.py, you are incorrectly passing ResultDocumentDetailView as an argument instead of a viewset.
Router while registering accepts a ViewSet instead of an APIView.
There are two mandatory arguments to the register() method:
prefix - The URL prefix to use for this set of routes.
viewset - The viewset class.
Also, since you are only interested in the retrieve method, you can just create a ResultDocumentRetrieveView and add its corresponding url to your urls.py without the need of creating a ResultDocument router. (Routers are generally used when you want to handle both list and detail requests.)
class ResultDocumentRetrieveView(generics.RetrieveAPIView):
queryset = Department.objects.all()
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
def retrieve(self, request, department_pk):
department = self.get_object()
...generate document logic...
return Response(status=status.HTTP_200_OK)
urls.py
url(r'^departments/(?P<department_pk>[0-9]+)/result/preview', ResultDocumentRetrieveView.as_view())

Queryset not displayed in django admin interface

I am creating a Django application and trying to include more search boxes in Django web admin interface for a specific model, so that users can simultaniously search more fields. For example, users can enter in one search box the name of the city, and in another search box the name of the street, and all model instances which have corresponding city and street are shown in browser after 'Search' button is hit. Default admin web interface has only one search box. I've added three search boxes in change_list.html file, and when I enter some data in those search boxes in browser and hit 'Search', a proper URL is formed (with query string containing those three input parameters by which the search shoould be done). Then I capture those input parameters in queryset method which I have overriden in my class that extends models.AdminModel calss, perform query set filtering and finally return the filtered queryset. Now, the problem is that the filtered query set is simply not shown on the web page (web interface of my model) after the search process is done, it says that no matches were found. But I am definately sure that my filtered query set contains data beacues I print it in command line just before the return command of queryset method is executed, and it prints correct data.
Here is my queryset method:
def queryset(self, request):
qs = super(UkopcanjeAdmin, self).queryset(request)
if "mjesto" in request.GET:
lokacija = request.GET.get('mjesto',None)
if lokacija:
qs = qs.filter(mjesto__icontains=lokacija)
if "ulica" in request.GET:
ulica = request.GET.get('ulica',None)
if ulica:
qs = qs.filter(ulica__icontains=ulica)
if "naziv" in request.GET:
naziv = request.GET.get('naziv',None)
if naziv:
qs = qs.filter(naziv__icontains=naziv)
print qs #this prints correct filtered data
return qs
Why isn't filtered query set shown in web interface?
EDIT : Thanks to my friend, I've finally managed to solve the problem. And solution is quite simple, all I had to do is move the whole code of queryset method to get_search_results method, and along filtered queryset return false boolean parameter (because get_search_results method returns two parameters). So if anybody wants to customize the search process in Django, the get_search_results method should be used. There you can access query string argumnets and retreive some data the way you want.
I think it should be get_queryset but not queryset method.
def get_queryset(request):
#your code here
queryset = super(UkopcanjeAdmin, self).get_queryset(request)
if 'miesto' in request.GET:
print 'Yes'
return queryset
else:
print 'No'
Here is some short explanation from Django docs.

Categories