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.
Related
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)
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())
I have a created a view class "class Demo", which has 3 functions
def update_time()
def get_context()
def before_response()
urls.py : url(r'^demo/$', Demo.as_view(),name='demo_class'),
When i'll enter url /demo/ how will it determine which function to call from "class Demo" ?
Because Django’s URL resolver expects to send the request and associated arguments to a callable function, not a class, class-based views have an as_view() class method which serves as the callable entry point to your class. The as_view entry point creates an instance of your class and calls its dispatch() method. dispatch looks at the request to determine whether it is a GET, POST, etc, and relays the request to a matching method if one is defined, or raises HttpResponseNotAllowed if not.
just read the docs
Basically class based views are recommended when you need to handle both get and post requests at one point. For example in get method of class Register, you can render the registration form and in its post method, you can handle the form submission. If its a get request it will automatically invoke the get() method in the class, same for post request. Also you can write any common code in the dispatch() method which will be invoked for every request.eg:
class Register(View):
def dispatch(self, *args, **kwargs):
'''
common code here
'''
return super(Register, self).dispatch(*args, **kwargs)
def get(self, request):
registration_form = RegistrationForm()
return render(request, 'new.html', { 'form': registration_form })
def post(self, request):
registration_form = RegistrationForm(request.POST or None)
if registration_form.is_valid():
#save form
return HttpResponseRedirect(reverse('success-show'))
return render(request,new.html', { 'form': registration_form })
For references you can check this website.
You need to subclass a class based views, and depending on that it will have one or another method.
For example TemplateView renders a template you pass in the template_name attribute.
All class based views care about is that the attributes needed to work properly are setted. That is done via different methods. You can check the django's documentation for specifics.
For example, if you want to render a form in your template view, you will need to pass the form in the context, so you can override get_context_data() like:
def get_context_data(self, **kwargs):
context = super(DemoClass, self).get_context_data(**kwargs)
context['form'] = MyForm()
return context
There are different methods to handle different things, like querysets, objects, etc.
They are not complicated, but they are specific. If a class based view does not fit what you need, it may be easier to implement the functionality from a more general view (View, TemplateView) than forcing a more specific one to do things it is not intended for.
slightly change the url
add numbers one to three in url and put the condition in your view.
Ex.
url(r'^abc/(?P<newid>.*)$', 'class_demo'),
so your url will be like abc/1 or abc/2 or abc/3
view
def class_demo(requests, newid):
if newid==1:
update_time()
elif newid==2:
get_context()
In Django I use:
return HttpResponseRedirect(reverse("admin:article_article_add"))
And I can see admin's "Add" page.
Can I somehow set values for fields of my model in this case?
Maybe it's impossible or maybe I didn't find it.
I want to predefine some fields when I redirect to "Add new" page
you could do it by passing some values in GET, but this wont work always(e.g. for datefields etc..), i would do it with custom ModelAdmins with get_form method
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['your_field_name'].initial = 'abcd'
return form
did you try simply adding it to a string?
reverse("admin:...")+"&fieldname=value"
you may need to use formating like this
return HttpResponseRedirect('%s%s'%(reverse("..."), '&field=value'))
depending on what your values are, you may need to also use a uri encoding routine (there are many ways to do this).
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.