I try to create a counter inside session but I fail. the session is print out the result I added once and it doesn't increment the process when I want to add a new comment again. the comment will be added but counter is still equal to one so, how can I do increment into session:
def post(self, request, user_slug, *args, **kwargs):
my_question = UserAsking.objects.get(ask_slug=user_slug)
userprof = UserProfile.objects.get(userasking__ask_slug=user_slug)
comment_form = CommentForm(request.POST, instance=request.user)
name = "%s %s" % (self.request.user.first_name, self.request.user.last_name)
username = self.request.user.username
logo = self.request.user.userprofile.logo.url
if comment_form.is_valid():
comment_request = self.request.POST.get('comment', None)
comment_form = Comment.objects.create(comment=comment_request,
userasking_id=my_question.id,
userprofile_id=userprof.id,
name=name,
username=username,
logo=logo,
comment_slug=my_question.ask_slug
)
q = UserAsking.objects.get(ask_slug=my_question.ask_slug)
c = comment_form
u = comment_form.userprofile
if 'notify_counts' in request.session:
counter = request.session.get('notify_counts', 0)
request.session['notify_counts'] = counter + 1
request.session.save()
print('%s is commented your post: %s and comment is (%s) notify = %i'
%(u, q, c, counter))
return redirect('community:question_view', user_slug)
# return redirect('community:question_view', comment_form.userasking.ask_slug)
return render(request, 'community/question_view.html', {'comment_form': comment_form})
Django automatically saves to the session database when the session has been modified, so you won't bother to save it manually, take a look:when session are stored[Django-Doc].
def post(request,...):
...
notify_counts = request.session.get('notify_counts')
if notify_counts is None:
request.session['notify_counts'] = 1
else:
request.session['notify_counts'] +=1
Also you could use try...except pattern as follows:
def post(request, ...):
try:
request.session['notify_counts'] +=1
except KeyError:
request.session['notify_counts'] = 1
Related
I have an Angular frontend that uses Apollo Graphql client to interface with a Django Graphql backend (using graphene). It all works well, but the API is very slow, especially when there are concurrent users. I am trying a few things to speed up the API server. One of the things that I am seriously considering is to use server-side caching.
I'm aware that there are some caching solutions that exist for Django out of the box, but these seem to be for caching the views. Is it possible to use these methods to cache Graphql API requests?
What is the most effective caching solution for caching the responses to graphql queries in Django?
I'm posting some of my project's code here so that you get a sense of how my API works.
This is a sample of the Query class containing the various graphql endpints that serve data when queries are received from the client. And I suspect this is where we'll need most of the optimization and caching applied:-
class Query(ObjectType):
# Public Queries
user_by_username = graphene.Field(PublicUserType, username=graphene.String())
public_users = graphene.Field(
PublicUsers, searchField=graphene.String(), membership_status_not=graphene.List(graphene.String), membership_status_is=graphene.List(graphene.String), roles=graphene.List(graphene.String), limit=graphene.Int(), offset=graphene.Int())
public_institution = graphene.Field(PublicInstitutionType, code=graphene.String())
public_institutions = graphene.Field(PublicInstitutions, searchField=graphene.String(), limit = graphene.Int(), offset = graphene.Int())
public_announcement = graphene.Field(AnnouncementType, id=graphene.ID())
public_announcements = graphene.List(
AnnouncementType, searchField=graphene.String(), limit=graphene.Int(), offset=graphene.Int())
def resolve_public_institution(root, info, code, **kwargs):
institution = Institution.objects.get(code=code, active=True)
if institution is not None:
public_institution = generate_public_institution(institution)
return public_institution
else:
return None
def resolve_public_institutions(root, info, searchField=None, limit=None, offset=None, **kwargs):
qs = Institution.objects.all().filter(public=True, active=True).order_by('-id')
if searchField is not None:
filter = (
Q(searchField__icontains=searchField.lower())
)
qs = qs.filter(filter)
total = len(qs)
if offset is not None:
qs = qs[offset:]
if limit is not None:
qs = qs[:limit]
public_institutions = []
for institution in qs:
public_institution = generate_public_institution(institution)
public_institutions.append(public_institution)
public_institutions.sort(key=lambda x: x.score, reverse=True) # Sorting the results by score before proceeding with pagination
results = PublicInstitutions(records=public_institutions, total=total)
return results
#login_required
def resolve_institution_by_invitecode(root, info, invitecode, **kwargs):
institution_instance = Institution.objects.get(
invitecode=invitecode, active=True)
if institution_instance is not None:
return institution_instance
else:
return None
#login_required
#user_passes_test(lambda user: has_access(user, RESOURCES['INSTITUTION'], ACTIONS['GET']))
def resolve_institution(root, info, id, **kwargs):
current_user = info.context.user
institution_instance = Institution.objects.get(pk=id, active=True)
allow_access = is_record_accessible(current_user, RESOURCES['INSTITUTION'], institution_instance)
if allow_access != True:
institution_instance = None
return institution_instance
#login_required
#user_passes_test(lambda user: has_access(user, RESOURCES['INSTITUTION'], ACTIONS['LIST']))
def resolve_institutions(root, info, searchField=None, limit=None, offset=None, **kwargs):
current_user = info.context.user
qs = rows_accessible(current_user, RESOURCES['INSTITUTION'])
if searchField is not None:
filter = (
Q(searchField__icontains=searchField.lower())
)
qs = qs.filter(filter)
total = len(qs)
if offset is not None:
qs = qs[offset:]
if limit is not None:
qs = qs[:limit]
results = Institutions(records=qs, total=total)
return results
#login_required
def resolve_user(root, info, id, **kwargs):
user_instance = User.objects.get(pk=id, active=True)
if user_instance is not None:
user_instance = redact_user(root, info, user_instance)
return user_instance
else:
return None
def resolve_user_by_username(root, info, username, **kwargs):
user = None
try:
user = User.objects.get(username=username, active=True)
except:
raise GraphQLError('User does not exist!')
courses = Report.objects.filter(active=True, participant_id=user.id)
if user is not None:
user = redact_user(root, info, user)
title = user.title if user.title else user.role.name
new_user = PublicUserType(id=user.id, username=user.username, name=user.name, title=title, bio=user.bio, avatar=user.avatar,institution=user.institution, courses=courses)
return new_user
else:
return None
def process_users(root, info, searchField=None, all_institutions=False, membership_status_not=[], membership_status_is=[], roles=[], unpaginated = False, limit=None, offset=None, **kwargs):
current_user = info.context.user
admin_user = is_admin_user(current_user)
qs = rows_accessible(current_user, RESOURCES['MEMBER'], {'all_institutions': all_institutions})
if searchField is not None:
filter = (
Q(searchField__icontains=searchField.lower()) | Q(username__icontains=searchField.lower()) | Q(email__icontains=searchField.lower())
)
qs = qs.filter(filter)
if membership_status_not:
qs = qs.exclude(membership_status__in=membership_status_not)
if membership_status_is:
qs = qs.filter(membership_status__in=membership_status_is)
if roles:
qs = qs.filter(role__in=roles)
redacted_qs = []
if admin_user:
redacted_qs = qs
else:
# Replacing the user avatar if the requesting user is not of the same institution and is not a super admin
for user in qs:
user = redact_user(root, info, user)
redacted_qs.append(user)
pending = []
uninitialized = []
others = []
for user in redacted_qs:
if user.membership_status == User.StatusChoices.PENDINIG:
pending.append(user)
elif user.membership_status == User.StatusChoices.UNINITIALIZED:
uninitialized.append(user)
else:
others.append(user)
sorted_qs = pending + uninitialized + others
total = len(sorted_qs)
if unpaginated == True:
results = Users(records=sorted_qs, total=total)
return results
if offset is not None:
sorted_qs = sorted_qs[offset:]
if limit is not None:
sorted_qs = sorted_qs[:limit]
results = Users(records=sorted_qs, total=total)
return results
#login_required
def resolve_users(root, info, searchField=None, membership_status_not=[], membership_status_is=[], roles=[], limit=None, offset=None, **kwargs):
all_institutions=False
unpaginated = False
qs = Query.process_users(root, info, searchField, all_institutions, membership_status_not, membership_status_is, roles, unpaginated, limit, offset, **kwargs)
return qs
def resolve_public_users(root, info, searchField=None, membership_status_not=[], membership_status_is=[], roles=[], limit=None, offset=None, **kwargs):
all_institutions=True
unpaginated = True
results = Query.process_users(root, info, searchField, all_institutions, membership_status_not, membership_status_is, roles, unpaginated, limit, offset, **kwargs)
records = results.records
total = results.total
public_users = []
# This is to limit the fields in the User model that we are exposing in this GraphQL query
for user in records:
courses = Report.objects.filter(active=True, participant_id=user.id)
score = 0
for course in courses:
score += course.completed * course.percentage
new_user = PublicUserType(id=user.id, username=user.username, name=user.name, title=user.title, bio=user.bio, avatar=user.avatar,institution=user.institution, score=score)
public_users.append(new_user)
public_users.sort(key=lambda x: x.score, reverse=True) # Sorting the results by score before proceeding with pagination
if offset is not None:
public_users = public_users[offset:]
if limit is not None:
public_users = public_users[:limit]
results = PublicUsers(records=public_users, total=total)
return results
I'm not sure what other code you'll need to see to get a sense, because the rest of the setup is typical of a Django application.
I have a django app that contains samples. On my home page, it displays a table with many samples, containing hyperlinks to the 'Sample page' - which is a view get request.
When I click on several of these samples in tandem, to open new tabs, each to a specific tab - I am getting cross over of data - I.e the url sample_id kwargs is different, but the page is displaying the same results which is incorrect. When i refresh the page, the correct sample data appears.
Is there any way around this happening is a user is to open several different sample tabs at the same time? This would impact on results and could cause errors in the workflow offered by the django app.
*is this because my view is processing too much, so the different view request=s ends up over lapping ?
Edit: adding view:
class FilterVariantSampleView(ReportView, ReportPDFGenerator, FileGenerator, limsQuery):
template_name = os.path.join(
'results',
'filter_templates',
'sample_page.html'
)
type = 'sample'
choice = False
group_required = ['filter']
def get(self, request, *args, **kwargs):
self.user = request.user
self.obtain_sample_information(kwargs)
self.obtain_patient_information()
self.obtain_header()
# create sample notes form
sample_notes_form = SampleNotesForm(
instance=self.sample_obj)
self.context['sample_notes_form'] = sample_notes_form
self.create_variant_filter_formset()
panel_list = [o.run_id.machine_panel_id.panel_id
for o in self.all_sr_obj]
if len(panel_list):
self.panel_obj = panel_list[0]
# self.generate_hotspot_form()
self.assess_fails()
crs_qs = ClinicallyReportedSample.objects.filter(
sample_id=self.sample_obj)
crs_qs = crs_qs.exclude(
reported_on_panel__parent_panel__isnull=False,
primary_technical_report=False,
final_technical_report=False
)
remove_report_form_list = []
lims_molecular_results = self.query_lims_clone_molecular(
qs=crs_qs)
mol_df = lims_molecular_results[0]
summary = lims_molecular_results[1]
self.context['summary'] = summary
if crs_qs.count() == 1:
crs_obj = crs_qs[0]
self.context['crs_qs'] = crs_qs
remove_report_form = RemoveDiagnosticReportForm(
instance=crs_obj)
remove_report_form_list.append(remove_report_form)
else:
messages.add_message(self.request, messages.WARNING,
'This sample has been sequenced on multiple panels.')
self.context['crs_qs'] = crs_qs
lims_molecular_results = self.query_molecular_lims(
sample_obj=self.sample_obj)
for crs_obj in crs_qs:
remove_report_form = RemoveDiagnosticReportForm(
instance=crs_obj)
remove_report_form_list.append(remove_report_form)
if crs_obj.diagnostic_report_required == False:
messages.add_message(self.request, messages.WARNING,
f'This sample does NOT require a diagnostic reoprt '
f'for the {crs_obj.reported_on_panel} panel.')
self.context['remove_report_form_list'] = remove_report_form_list
return render(request, self.template_name, self.context)
def post(self, request, *args, **kwargs):
"""
"""
self.define_variant_filter_formset()
submit = request.POST.get('submit', None)
if submit:
if submit == 'Modify sample':
logger.info('')
logger.info('Sample: {}'.format(self.sample_obj))
logger.info("Submit: '{}'".format(submit))
# pass POST dict to formset
modify_formset = self.CRVFormSet(request.POST, prefix='crv')
# validate
if modify_formset.is_valid():
logger.info('Modify Variant Formset valid')
logger.info('')
self.modify_variants(modify_formset)
self.modify_sample()
return HttpResponseRedirect(
reverse('results:filter_variant_sample',
kwargs={'sample_id': self.sample_obj.id}))
else:
msg = ('Modify ClinicallyReportedVariant '
f'Formset NOT valid: {modify_formset.errors}')
logger.error(msg)
messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(
reverse('results:filter_variant_sample',
kwargs={'sample_id': self.sample_obj.id}))
elif submit == 'Update':
form = RemoveDiagnosticReportForm(request.POST,
instance=ClinicallyReportedSample.objects.get(
sample_id=kwargs['sample_id'],
reported_on_panel=request.POST['reported_on_panel'])
)
if form.is_valid():
logger.info('RemoveDiagnosticReportForm is valid')
try:
form.save()
except Exception as e:
logger.error(e)
else:
msg = f'RemoveDiagnosticReportForm is NOT valid: {form.errors}'
logger.error(msg)
messages.add_message(self.request, messages.ERROR, msg)
return HttpResponseRedirect(request.path_info)
elif 'Download' in submit:
panel_name = submit.split(' ')[1]
self.panel_obj = Panel.objects.get(panel_name=panel_name)
self.crs_obj = ClinicallyReportedSample.objects.get(
sample_id=self.sample_obj, reported_on_panel=self.panel_obj)
if 'panel data' in submit:
logger.info(f'Downloading data for {self.sample_obj}')
if self.crs_obj.sample_id.external_dept.site in ['Newcastle', 'Sheffield']:
downloaded_data = self.download_yne_data()
if downloaded_data:
self.crs_obj.downloaded_data = True
self.crs_obj.downloaded_data_user = request.user
self.crs_obj.downloaded_data_date = timezone.now()
self.crs_obj.save()
return downloaded_data
else:
return HttpResponseRedirect(self.request.path_info)
elif 'report' in submit:
logger.info(f'Downloading report for {self.sample_obj}')
# update crs_obj
self.crs_obj.download_technical_report = True
self.crs_obj.download_technical_report_user = self.user
self.crs_obj.download_technical_report_date = timezone.now()
self.crs_obj.save()
# return HttpResponseRedirect(self.request.path_info)
lims_molecular_results = self.query_molecular_lims(
sample_obj=self.sample_obj)
mol_df = lims_molecular_results[0]
summary = lims_molecular_results[1]
if mol_df.empty:
logger.info('No molecular tests done')
self.latex_context['gene_status'] = False
else:
gene = mol_df[
(mol_df['test_name'] == 'gene') &
(mol_df['status'] == 'complete')
]
if gene.empty:
self.context['gene'] = False
else:
msg = ("gene Sanger in-fill test has been completed.{}")
result = gene['result'].to_string(index=False)
if result == 'normal or wild-type':
msg = msg.format(' No detectable variants.')
msg_info = messages.INFO
gene_df = pd.DataFrame()
elif result == 'failed':
msg = msg.format(' Unfortunately the test failed.')
msg_info = messages.WARNING
gene_df = pd.DataFrame()
elif result == 'mutated' or result == 'suspicious':
gene_df = self.get_gene_result(gene, technical_report=True)
if result == 'suspicious':
msg = msg.format(' There is suspicion of a variant '
'(see below for more information).')
else:
msg = msg.format(' A variant was detected '
'(see below for more information).')
msg_info = messages.INFO
else:
msg = msg.format(' Error - contact administrator.')
msg_info = messages.ERROR
result = 'error'
gene_df = pd.DataFrame()
self.latex_context['gene_status'] = result
self.latex_context['gene_df'] = gene_df
logger.info(msg)
messages.add_message(self.request, msg_info, msg)
print(self.latex_context)
# call method from TechnicalReportPDFGenerator
self.generateReport(report_type='technical')
response = self.download_technical_report()
return response
return render(request, self.template_name, self.context)
This may be due to the cache of your browser, are you sure the calls are going through the first time ?
I'm having to do some validation across both a form and formset. The £££ amount in the form must equal the sum of the amounts in the formset.
After a lot of Googling I found a solution where I add a custom init to the baseformset as follows:
class BaseSplitPaymentLineItemFormSet(BaseFormSet):
def __init__(self, cr=None, *args, **kwargs):
self._cr = cr
super().__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
return
sum_dr = 0
for form in self.forms:
sum_dr += form.cleaned_data.get('dr')
if sum_dr != float(self._cr):
raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
I then pass the amount value from the form when the formset is instantiated, so that the value can be used in the formset validation:
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
This worked great for the create_new view which uses formset_factory(). This morning I wrote the update view using inline_formsetfactory(), but I now get an error:
__init__() got an unexpected keyword argument 'instance'
I only have a basic understanding of how the custom init works, so I can't find a solution to this error.
Forms.py:
class SplitPaymentForm(forms.Form):
date = forms.DateField(widget=DateTypeInput())
account = GroupedModelChoiceField(queryset=Ledger.objects.filter(coa_sub_group__type='a').order_by('coa_sub_group__name','name'), choices_groupby = 'coa_sub_group')
store = forms.CharField(required=True)
amount = forms.DecimalField(decimal_places=2)
class SplitPaymentLineItemForm(ModelForm):
ledger = GroupedModelChoiceField(queryset=Ledger.objects.all().order_by('coa_sub_group__name', 'name'), choices_groupby = 'coa_sub_group', empty_label="Ledger", required=True)
project = forms.ModelChoiceField(queryset=Project.objects.filter(status=0), empty_label="Project", required=False)
class Meta:
model = LineItem
fields = ['description','project', 'ledger','dr',]
# This init disallows empty formsets
def __init__(self, *arg, **kwarg):
super(SplitPaymentLineItemForm, self).__init__(*arg, **kwarg)
self.empty_permitted = False
class BaseSplitPaymentLineItemFormSet(BaseFormSet):
def __init__(self, cr=None, *args, **kwargs):
self._cr = cr
super().__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
return
sum_dr = 0
for form in self.forms:
sum_dr += form.cleaned_data.get('dr')
if sum_dr != float(self._cr):
raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
Views.py:
def split_payments_new(request):
LineItemFormSet = formset_factory(SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=2)
if request.method == 'POST':
form = SplitPaymentForm(request.POST)
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
if form.is_valid() and lineitem_formset.is_valid():
q0 = JournalEntry(user=request.user, date=form.cleaned_data['date'], type="SP",)
q1 = LineItem(journal_entry=q0, description=form.cleaned_data['store'], ledger=form.cleaned_data['account'], cr=form.cleaned_data['amount'])
q0.save()
q1.save()
for lineitem in lineitem_formset:
q2 = LineItem(journal_entry=q0,description=lineitem.cleaned_data.get('description'),ledger=lineitem.cleaned_data.get('ledger'),project=lineitem.cleaned_data.get('project'),dr=lineitem.cleaned_data.get('dr'))
q2.save()
messages.success(request, "Split payment successfully created.")
return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': q0.id}) )
else:
form = SplitPaymentForm(initial = {'date': datetime.date.today().strftime('%Y-%m-%d')})
lineitem_formset = LineItemFormSet()
return render(request, 'journal/split_payments_new.html', {'form': form, 'formset': lineitem_formset})
def split_payments_update(request, pk):
journal_entry = get_object_or_404(JournalEntry, pk=pk, type="SP")
lineitem = LineItem.objects.get(journal_entry=journal_entry.id, dr__isnull=True)
initial = {
'date': journal_entry.date.strftime('%Y-%m-%d'),
'account': lineitem.ledger,
'store': lineitem.description,
'amount': lineitem.cr,
}
form = SplitPaymentForm(initial=initial)
LineItemFormSet = inlineformset_factory(JournalEntry, LineItem, form=SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=0)
lineitem_formset = LineItemFormSet(instance=journal_entry)
if request.method == 'POST':
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST, instance=journal_entry)
form = SplitPaymentForm(request.POST)
if lineitem_formset.is_valid() and form.is_valid():
lineitem_formset.save()
journal_entry.date = form.cleaned_data['date']
lineitem.ledger = form.cleaned_data['account']
lineitem.description = form.cleaned_data['store']
lineitem.cr = form.cleaned_data['amount']
journal_entry.save()
lineitem.save()
messages.success(request, "Split payment successfully updated.")
return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': journal_entry.id}) )
return render(request, 'journal/split_payments_update.html',{'form': form, 'formset': lineitem_formset, 'journal_entry': journal_entry})
Solved. Just had to use BaseInlineFormSet.
I was trying to dynamically generate fields as shown in http://jacobian.org/writing/dynamic-form-generation/. My case slightly differs in that I am looking to use multiplechoicefield that is dynamically created. This is what I came up with...
views.py
def browseget(request):
success = False
if request.method == 'POST':
list_form = ListForm(request.POST)
if list_form.is_valid():
success = True
path = list_form.cleaned_data['path']
minimum_size = list_form.cleaned_data['minimum_size']
follow_link = list_form.cleaned_data['follow_link']
checkboxes = list_form.cleaned_data['checkboxes']
....do something
else:
list_form = ListForm(name_list)
ctx = {'success': success, 'list_form': list_form, 'path': path, 'minimum_size': minimum_size}
return render_to_response('photoget/browseget.html', ctx, context_instance=RequestContext(request))
forms.py
class ListForm(forms.Form):
path = forms.CharField(required=False)
minimum_size = forms.ChoiceField(choices=size_choices)
follow_link = forms.BooleanField(required=False, initial=True)
def __init__(self, *args, **kwargs):
name_list = kwargs.pop('name_list', None)
super(ListForm, self).__init__(*args, **kwargs)
print 'Received data:', self.data
if name_list:
name_choices = [(u, u) for u in name_list]
self.fields['checkboxes'] = forms.MultipleChoiceField(required=False, label='Select Name(s):', widget=forms.CheckboxSelectMultiple(), choices=name_choices)
def clean_path(self):
cd = self.cleaned_data
path = cd.get('path')
if path == '': path = None
return path
def clean_minimum_size(self):
cd = self.cleaned_data
minimum_size = cd.get('minimum_size')
if minimum_size is None: minimum_size = 0
return int(minimum_size)
The form generates and displays perfectly... until I post some data. The 'checkboxes' field doesn't show up in list_form.cleaned_data.items() while it shows in self.data. As it is the form breaks with a KeyError exception. So Im asking, how do i access the checkboxes data?
You're not passing in the name_list parameter when you re-instantiate the form on POST, so the field is not created because if name_list is False.
middleware.py
def get_perpage(self):
try:
self.session['perpage'] = int(self.REQUEST['perpage'])
return self.session['perpage']
except (KeyError, ValueError, TypeError):
pass
try:
return int(self.session['perpage'])
except (KeyError, ValueError, TypeError):
return DEFAULT_PAGINATION
I have a problem: when i want to turn zero into URL as GET parameter (?perpage=0), it shows me ZeroDivisionError float division by zero. I need to take ALL objects on page without pagination when perpage=0. How can I do this? What is must be in view.py?
def render(self, context):
key = self.queryset_var.var
value = self.queryset_var.resolve(context)
if (self.paginate_by == None):
paginate_by = int(context['request'].perpage)
else:
paginate_by = self.paginate_by.resolve(context)
if (paginate_by == 0): #HERE
context['page_obj'] = value # IS
return u'' #SOLUTION
print (paginate_by)
paginator = Paginator(value, paginate_by, self.orphans)
try:
page_obj = paginator.page(context['request'].page)
except InvalidPage:
if INVALID_PAGE_RAISES_404:
raise Http404('Invalid page requested. If DEBUG were set to ' +
'False, an HTTP 404 page would have been shown instead.')
context[key] = []
context['invalid_page'] = True
return u''
if self.context_var is not None:
context[self.context_var] = page_obj.object_list
else:
context[key] = page_obj.object_list
context['paginator'] = paginator
context['page_obj'] = page_obj
return u''
when my view gets perpage=0, it returns pure object list (value) without Pagination to template