What does request.GET.get('page', '1') means here? - python

views.py
from django.core.paginator import Paginator
def index(request):
posts_list = Post.objects.all().order_by('-id')
paginator = Paginator(posts_list, 5)
try:
page = int(request.GET.get('page', '1'))
except:
page = 1
try:
posts = paginator.page(page)
except(EmptyPage, InvalidPage):
posts = paginator.page(paginator.num_pages)
return render_to_response('home/index.html',
{ 'posts' : posts },
context_instance=RequestContext(request))

Well this is a mix between Python's get method features and GET of Django,
Basically, since GET is a A dictionary-like object containing all given HTTP GET parameters, what you are trying to achieve here is find the value for the given key 'page'. If it doesn't exist it will fallback to the default value 1 which is what get intends to do.

In simple way... you are using get() method that will check if the element that you want exists if not return None (null), so you are searching for GET (HTTP) Paramter if "page" exists, if not exists it return 1
mypage.com/?page=2
request.GET['page'] # That will force get page param, and you will if not found
request.GET.get('page', '1') # Tha will check if param exists, and return 1 if not found
Using GET.get() is a bad pratice, since your erros will silent fail, better your GET['page'] and handle the errors using try/except
try:
page = request.GET['page']
...
except Exception as e:
print(e) # handle your errors
page = 1 # The Default value when erros comes
...

Related

Rendering a "<class 'django.template.response.TemplateResponse'>" Object in Django

I have a requirement to incorporate my existing working openstack horizon with our SSO using python-saml.
Hence i referred to demo docs which is written here:
https://github.com/onelogin/python-saml/blob/master/demo-django/demo/views.py#L113
So here as per the guide, I need to render the page as mentioned.
return render(request, 'auth/login.html', {'errors': errors, 'not_auth_warn': not_auth_warn, 'success_slo': success_slo, 'paint_logout': paint_logout, 'SSO': True})
When I am trying the same I am not getting the expected result on page, to be exact, I am not getting the exact desired page with full details. here is the more detail on the same.
Expected page(This is screenshot of page working fine, before i am enabling saml):
Actual page now(Username and password text box not visible, Because login.html file is not enough to render it, because it need form to fully display, using django_auth_views response object "res" is created for the same):
Code:
def login(request, template_name=None, extra_context=None, **kwargs):
"""Logs a user in using the :class:`~openstack_auth.forms.Login` form."""
if not request.is_ajax():.
if (request.user.is_authenticated() and
auth.REDIRECT_FIELD_NAME not in request.GET and
auth.REDIRECT_FIELD_NAME not in request.POST):
return shortcuts.redirect(settings.LOGIN_REDIRECT_URL)
# Get our initial region for the form.
initial = {}
current_region = request.session.get('region_endpoint', None)
requested_region = request.GET.get('region', None)
regions = dict(getattr(settings, "AVAILABLE_REGIONS", []))
if requested_region in regions and requested_region != current_region:
initial.update({'region': requested_region})
if request.method == "POST":
if django.VERSION >= (1, 6):
form = functional.curry(forms.Login)
else:
form = functional.curry(forms.Login, request)
else:
form = functional.curry(forms.Login, initial=initial)
if extra_context is None:
extra_context = {'redirect_field_name': auth.REDIRECT_FIELD_NAME}
if not template_name:
if request.is_ajax():
template_name = 'auth/_login.html'
extra_context['hide'] = True
else:
template_name = 'auth/login.html'
res = django_auth_views.login(request,
template_name=template_name,
authentication_form=form,
extra_context=extra_context,
**kwargs)
# Save the region in the cookie, this is used as the default
# selected region next time the Login form loads.
if request.method == "POST":
utils.set_response_cookie(res, 'login_region',
request.POST.get('region', ''))
req = prepare_django_request(request)
auth = init_saml_auth(req)
errors = []
not_auth_warn = False
success_slo = False
attributes = False
paint_logout = False
if 'sso' in req['get_data']:
return HttpResponseRedirect(auth.login())
elif 'slo' in req['get_data']:
name_id = None
session_index = None
if 'samlNameId' in request.session:
name_id = request.session['samlNameId']
if 'samlSessionIndex' in request.session:
session_index = request.session['samlSessionIndex']
slo_built_url = auth.logout(name_id=name_id, session_index=session_index)
request.session['LogoutRequestID'] = auth.get_last_request_id()
print ('set logout id'+auth.get_last_request_id())
return HttpResponseRedirect(slo_built_url)
if 'samlUserdata' in request.session:
paint_logout = True
if len(request.session['samlUserdata']) > 0:
attributes = request.session['samlUserdata'].items()
return render(request, 'auth/login.html', {'errors': errors, 'not_auth_warn': not_auth_warn, 'success_slo': success_slo, 'paint_logout': paint_logout, 'SSO': True})
Would like to know what may be the problem here, What can be the fix to overcome this issue.
I have given try as below, tried returning the TemplateResponse object which was created in above mentioned code correct working code was just returning 'res' object from code.
return res
hence I tried to return the object instead of html file. ie: 'res' instead of 'auth/login.html'.
return render(request, res, {'errors': errors, 'not_auth_warn': not_auth_warn, 'success_slo': success_slo, 'paint_logout': paint_logout, 'SSO': True})
It returns error as follow:
Getting an error as follows:
ContentNotRenderedError at /auth/login/
The response content must be rendered before it can be accessed.
During analysis, I can see that template object(res), Which is of type: class 'django.template.response.TemplateResponse'
Someone please drop thoughts to figure out how we can resolve.

How to combine bootstrap paginator and select to filter a table?

I currently use paginator on a table. I want to add a select to filter the table but I do not manage how to navigate through pages without loosing my selection.
Currently (see code below) when I navigate by clicking on previous or next, option selected by used is lost and all data are presented.
I must change the 'else' condition to take account the option selected. I was thinking about using global variable to store option selected in a variable but it can have side-effect and it is not so recommended...
views.py
#login_required
def index(request):
# data sent (click on 'search' button or option selected)
if request.POST:
# data from select
selection = request.POST.get('selection', False)
# data from search
ide = request.POST.get('ide', False)
# search
if ide == "":
paginator = Paginator(Preinclusion.objects.all(), 5)
preincluded = paginator.page(1)
else:
paginator = Paginator(Preinclusion.objects.filter(pat_num__startswith = ide),5)
preincluded = paginator.page(1)
# select
if selection == 'Randomized':
print('Randomized')
paginator = Paginator([patient for patient in Preinclusion.objects.all() if patient.is_randomized], 5)
preincluded = paginator.page(1)
elif selection == 'Not randomized':
print('Not randomized')
paginator = Paginator([patient for patient in Preinclusion.objects.all() if not patient.is_randomized], 5)
preincluded = paginator.page(1)
elif selection == 'All patients':
print('All patients')
paginator = Paginator(Preinclusion.objects.all(), 5)
preincluded = paginator.page(1)
if not preincluded:
liste_existe = False # non utilisé dans le template
else:
# first index visited
paginator = Paginator(Preinclusion.objects.all(), 5)
page = request.GET.get('page')
try:
preincluded = paginator.page(page)
except PageNotAnInteger:
preincluded = paginator.page(1)
except EmptyPage:
preincluded = paginator.page(paginator.num_pages)
return render(request, 'randomization/index.html', {'preincluded': preincluded})
I would like to store selected option for previous/next navigation.
you can use Django session to store whatever you want, example: request.session['my_key'] = 'My Value'
Just pass your 'selection' attribute to a render context like this
return render(request, 'randomization/index.html', {'preincluded': preincluded, 'selection': selection})
Then, process this context variable in template ({{ selection }}), and set selected option by this value. One of possible variants will be just like this:
<select>
<option value="Randomized" {% if selection == "Randomized" %}selected{% endif %}>1</option>
</select>
As you said, avoid to use global variables in asynchronous and stateless applications

UnboundLocalError:local variabel 'socialhandle' referenced before assignment

I'm working on a django project and i'm trying to fetch data from the database, according to some primary key value. However when the object exists in the DB then everything is working fine but when it doesn't then django is raising:
UnboundLocalError: local variable 'socialhandle' referenced before assignment.
Here is my django view:
def profile(request, profile_id):
"""View for returning a unique profile"""
profile = get_object_or_404(UserProfile, pk=profile_id)
try:
socialhandle = SocialPlatform.objects.get(user_id=profile_id)
except socialhandle.DoesNotExist:
socialhandle = None
context = {
'profile' : profile,
'socialhandle' : socialhandle,
}
return render(request, 'profiles/profile.html', context)
You cannot access socialhandle.DoesNotExist in the except block because if the try does not interpret successfully, socialhandle would still be undefined.
Solution 1: Use Django's standard exception for this case:
from django.core.exceptions import ObjectDoesNotExist
...
try:
socialhandle = SocialPlatform.objects.get(user_id=profile_id)
except ObjectDoesNotExist:
socialhandle = None
Solution 2: Look at the answer of #JPG
The proper way of handling the DoesNotExist is,
try:
...
except SomeModel.DoesNotExist:
...
Where the SomeModel should be the model class, not the model "instance"
So,
use except SocialPlatform.DoesNotExist instead of except socialhandle.DoesNotExist
def profile(request, profile_id):
"""View for returning a unique profile"""
profile = get_object_or_404(UserProfile, pk=profile_id)
try:
socialhandle = SocialPlatform.objects.get(user_id=profile_id)
except SocialPlatform.DoesNotExist:
socialhandle = None
context = {
'profile' : profile,
'socialhandle' : socialhandle,
}
return render(request, 'profiles/profile.html', context)

Python elasticsearch-dsl django pagination

How can i use django pagination on elasticsearch dsl.
My code:
query = MultiMatch(query=q, fields=['title', 'body'], fuzziness='AUTO')
s = Search(using=elastic_client, index='post').query(query).sort('-created_at')
response = s.execute()
// this always returns page count 1
paginator = Paginator(response, 100)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
Any solution for this?
I found this paginator on this link:
from django.core.paginator import Paginator, Page
class DSEPaginator(Paginator):
"""
Override Django's built-in Paginator class to take in a count/total number of items;
Elasticsearch provides the total as a part of the query results, so we can minimize hits.
"""
def __init__(self, *args, **kwargs):
super(DSEPaginator, self).__init__(*args, **kwargs)
self._count = self.object_list.hits.total
def page(self, number):
# this is overridden to prevent any slicing of the object_list - Elasticsearch has
# returned the sliced data already.
number = self.validate_number(number)
return Page(self.object_list, number, self)
and then in view i use:
q = request.GET.get('q', None)
page = int(request.GET.get('page', '1'))
start = (page-1) * 10
end = start + 10
query = MultiMatch(query=q, fields=['title', 'body'], fuzziness='AUTO')
s = Search(using=elastic_client, index='post').query(query)[start:end]
response = s.execute()
paginator = DSEPaginator(response, settings.POSTS_PER_PAGE)
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
this way it works perfectly..
Following the advice from Danielle Madeley, I also created a proxy to search results which works well with the latest version of django-elasticsearch-dsl==0.4.4.
from django.utils.functional import LazyObject
class SearchResults(LazyObject):
def __init__(self, search_object):
self._wrapped = search_object
def __len__(self):
return self._wrapped.count()
def __getitem__(self, index):
search_results = self._wrapped[index]
if isinstance(index, slice):
search_results = list(search_results)
return search_results
Then you can use it in your search view like this:
paginate_by = 20
search = MyModelDocument.search()
# ... do some filtering ...
search_results = SearchResults(search)
paginator = Paginator(search_results, paginate_by)
page_number = request.GET.get("page")
try:
page = paginator.page(page_number)
except PageNotAnInteger:
# If page parameter is not an integer, show first page.
page = paginator.page(1)
except EmptyPage:
# If page parameter is out of range, show last existing page.
page = paginator.page(paginator.num_pages)
Django's LazyObject proxies all attributes and methods from the object assigned to the _wrapped attribute. I am overriding a couple of methods that are required by Django's paginator, but don't work out of the box with the Search() instances.
A very simple solution is to use MultipleObjectMixin and extract your Elastic results in get_queryset() by overriding it. In this case Django will take care of the pagination itself if you add the paginate_by attribute.
It should look like that:
class MyView(MultipleObjectMixin, ListView):
paginate_by = 10
def get_queryset(self):
object_list = []
""" Query Elastic here and return the response data in `object_list`.
If you wish to add filters when querying Elastic,
you can use self.request.GET params here. """
return object_list
Note: The code above is broad and different from my own case so I can not guarantee it works. I used similar solution by inheriting other Mixins, overriding get_queryset() and taking advantage of Django's built in pagination - it worked great for me. As it was an easy fix I decided to post it here with a similar example.
Another way forward is to create a proxy between the Paginator and the Elasticsearch query. Paginator requires two things, __len__ (or count) and __getitem__ (that takes a slice). A rough version of the proxy works like this:
class ResultsProxy(object):
"""
A proxy object for returning Elasticsearch results that is able to be
passed to a Paginator.
"""
def __init__(self, es, index=None, body=None):
self.es = es
self.index = index
self.body = body
def __len__(self):
result = self.es.count(index=self.index,
body=self.body)
return result['count']
def __getitem__(self, item):
assert isinstance(item, slice)
results = self.es.search(
index=self.index,
body=self.body,
from_=item.start,
size=item.stop - item.start,
)
return results['hits']['hits']
A proxy instance can be passed to Paginator and will make requests to ES as needed.

Get current page of pagination in view and manually set count of page

I need to manually set count of page for pagination in view.py
I need to get number of current page for processing it in function.
I next view.py:
class VideoListView(ListView):
template_name = "video/list.html"
context_object_name = 'videos'
paginate_by = 12
request = requests.get(settings.YOUTUBE_VIDEO_COUNT_URL)
count = simplejson.loads(request.text)['data']['totalItems']
def get_queryset(self, **kwargs):
request = requests.get(settings.YOUTUBE_VIDEO_URL)
data_about = simplejson.loads(request.text)
video_list = []
for item in data_about['data']['items']:
video_list.append(item)
return video_list
Count of pages must be: count/paginate_by, and on every page request json will be different.
The Django pagination is stored via GET, so in your ListView you need to access:
# This will assume, if no page selected, it is on the first page
actual_page = request.GET.get('page', 1)
if actual_page:
print actual_page
so in your list view code, depends on where you need it, but if you need it in your get_queryset function, you can access the request using self:
class VideoListView(ListView):
# ..... your fields
def get_queryset(self, **kwargs):
# ... Your code ...
actual_page = self.request.GET.get('page', 1)
if actual_page:
print actual_page
# ... Your code ...
Custom pagination object using Django Pagination:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def CreatePagination(request, obj_list):
# Create the pagination
RESULTS_PER_PAGE = 10
paginator = Paginator(obj_list, RESULTS_PER_PAGE)
page = request.GET.get('page') # Actual page
try:
page_list = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
page_list = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
page_list = paginator.page(paginator.num_pages)
return page_list
To use this CreatePagination function you need to pass it the request and the object list. The request is used to get the actual page, and the object list is used to generate the pagination.
This function will return a pagination that you can manage in the template the same way you're managing the automatic generated pagination from the ListView

Categories

Resources