Django model property with dictionary data - django

I'm trying to access a property/computed field that contains a dictionary within my template I'm not quite sure on how I should be looping over the values, and from a code standpoint is this the correct way to go... As you can see below, my view creates a filter queryset and my hope is that each row within that queryset will contain the dict from the computed field/property from the model. Any advice would be greatly appreciated. I'm having a hard time determining what would be the correct way to loop over the data in the template itself. The final product would look something like this...
<div id={{provider.id}}>{{provider.name}}</div>
<div class="dayofweek">Monday</div>
<div class="timesavailable">
<ul>
<li>8:00</li>
<li>8:30></li>
</div>
Model:
from project.lib.file import GetSchedule
class Provider(models.Model):
....
#property
def current_schedule(self):
sched = GetSchedule(self.id)
return sched.returnSchedule()
Helper Function:
class GetSchedule(object):
schedule = {}
def __init__(self, provider_id):
self.provider = provider_id
try:
self.schedule = GetSchedule.__buildSchedule(self,self.provider)
except ObjectDoesNotExist:
print "Init failed - Cannot find provider in db with id: %s" % self.provider
raise ValueError
def __buildSchedule(self, provider):
#default values for now - dict will contain data soon
pid = self.provider
sched = {'Monday':{'8:00','8:30','10:00'}, 'Tuesday':{'10:00','10:30','11:00'}, 'Wednesday':{'9:30','10:00','10:30'}}
val = {
'Schedule' : sched
}
return val
def returnSchedule(self):
return self.schedule
View:
prov_list = Provider.objects.filter(docspeciality__name=dft_spec)
context_dict = {
'DftSpec': dft_spec,
'DftZip': dft_zip,
'DftIns': dft_ins,
'DocList': prov_list}
return render_to_response('search/provider.html', context_dict, context_instance=RequestContext(request))

Related

Using UUID in View_Detail page in Django

I have an app that is working fine, but i just changed the ID to UUIDm and the route no longer work.
I have the following route:
path("documents/uuid:uuid/",views.document_show, name="document_show"),
and the following view:
def document_show(request, id):
student_list = DocumentAttachment.objects.all()
for student in student_list:
print("we are printing the list of imaged uploaded :", student.attachment)
context = {}
try:
context["data"] = Document.objects.get(id=id)
except Document.DoesNotExist:
raise Http404('Book does not exist')
return render(request, "documents/show.html", context)
With the architecture: template/documents/show.html
May I ask what is the right way to setup the routes please?
Firstly as pointed out by #Boma Anjang in their comment you missed the <> symbols in your pattern which then should be:
path("documents/<uuid:uuid>/",views.document_show, name="document_show"),
Next your view is defined as document_show(request, id) this needs to be updated as the captured arguments are passed as keyword arguments to the view and hence need to have the correct name.
Similarly Document.objects.get(id=id) also needs to be updated.
Hence your view should be something like:
def document_show(request, uuid):
student_list = DocumentAttachment.objects.all()
for student in student_list:
print("we are printing the list of imaged uploaded :", student.attachment)
context = {}
try:
context["data"] = Document.objects.get(uuid=uuid) # Not sure of the name of your field for the uuid, edit as per the name
except Document.DoesNotExist:
raise Http404('Book does not exist')
return render(request, "documents/show.html", context)

Flask Admin - is there a way to store current url (with custom filters applied) of table view?

I am working on ticketing system in Flask Admin. The Flask Admin enviroment will be the main one for all the users. For creating or editing tickets I go out from Flask-Admin and use wtforms to implement backend logic. After creation or editing the ticket (validate_on_submit) I want to redirect back to Flask Admin, so I use redirect(url_for(ticket.index_view)). It works fine.
Is there a way to redirect to flask admin, but also with specific filters which were applied before user left Flask admin enviroment? (it is basiccaly GET parameters of url - but in FLASK)
I was trying to use:
referrer = request.referrer
get_url()
But I am probably missing something crucial and don´t know how to implement it (where to put it so I can call the arguments)
Thank you so much.
EDIT : adding more context:
I have a flask admin customized to different roles of users. The main ModelView is the one showing the TICKETS : the specifics of the Class are not vital to my current problem but here its how it looks:
class TicketModelView(ModelView):
column_list = ['id', 'title', 'osoba', 'content', 'povod_vmc_kom', 'dateVMC','zodpovedni', 'deadline', 'odpoved', 'solution', 'is_finished']
column_searchable_list = ['osoba']
column_filters = [ 'povod_vmc_kom', 'dateVMC', 'osoba', 'zodpovedni']
column_labels = dict(povod_vmc_kom='VMČ / Komisia', dateVMC='Dátum VMČ / komisie', zodpovedni = "Zodpovední")
column_display_actions = True
column_filters = [
FilterEqual(column=Ticket.povod_vmc_kom, name='Výbor/komisia', options=(('VMČ Juh','VMČ Juh'), ('UM','UM'), ('Kom dopravy','Kom dopravy'))),
'zodpovedni', 'is_finished',
'dateVMC', 'osoba'
]
def is_accessible(self):
#práva pre vedenie mesta - môže len nazerať
if current_user.is_authenticated and current_user.role == 0:
self.can_export=True
self.can_delete = False
self.can_edit = False
self.can_create = False
self._refresh_form_rules_cache()
self._refresh_forms_cache()
return True
#práva pre super admina (ostatné práva sú defaultne zapnuté)
if current_user.is_authenticated and current_user.role == 1:
self.can_export=True
self.can_delete=True
self.form_edit_rules = ('zodpovedni', 'is_finished' )
self.column_editable_list = ['is_finished']
self._refresh_form_rules_cache()
self._refresh_forms_cache()
return True
#práva pre garantov
if current_user.is_authenticated and current_user.role == 2:
self.can_delete = False
self.can_create = False
self.can_edit = False
self.can_export=True
self.column_searchable_list = ['title']
self._refresh_form_rules_cache()
self._refresh_forms_cache()
return True
#práva pre veducich utvarov
if current_user.is_authenticated and current_user.role == 3:
self.can_create = False
self.can_delete = False
self.can_export=True
self.column_searchable_list = ['title']
self.column_editable_list = ['odpoved', 'date_odpoved', 'solution', 'date_solution' ]
self.form_edit_rules = ('odpoved', 'date_odpoved', 'solution', 'date_solution')
self._refresh_form_rules_cache()
self._refresh_forms_cache()
return True
return False
def _solution_formatter(view, context, model, name):
# Format your string here e.g show first 20 characters
# can return any valid HTML e.g. a link to another view to show the detail or a popup window
if model.solution:
return model.solution[:50]
pass
def _content_formatter(view, context, model, name):
# Format your string here e.g show first 20 characters
# can return any valid HTML e.g. a link to another view to show the detail or a popup window
if len(model.content) > 100:
markupstring = "<a href= '%s'>%s</a>" % (url_for('ticket', ticket_id=model.id), "...")
return model.content[:100] + Markup(markupstring)
return model.content
def _user_formatter(view, context, model, name):
if model.id:
markupstring = "<a href= '%s'>%s</a>" % (url_for('ticket', ticket_id=model.id), model.id)
return Markup(markupstring)
else:
return ""
column_formatters = {
'content': _content_formatter,
'solution': _solution_formatter,
'id': _user_formatter
}
When user viewing the TicketView in Flask Admin, he can apply various filters which is vital to the user experience of the whole web app. The filters work fine and they are stored in URL as GET arguments. When he wants to create or edit a ticket, I am not allowing him to do it in Flask Admin (I edited Flask-Admin layout.html template and added a button to navbar which redirects to my new_ticket url with wtforms.) because of backend logic I want to be applied. For example when he edits field "solution" : I want the value in field "date_of_solution" be generated automatically (date.today()). So I am using wtforms and flask routing : example is bellow:
#app.route("/ticket/<int:ticket_id>/solution", methods = ['GET', 'POST'])
#login_required
def solution(ticket_id):
if current_user.role != 3:
flash("Pre zadanie riešenia alebo odpovede musíte byť prihlásený ako vedúci útvaru", "danger")
return redirect(url_for('ticket', ticket_id=ticket_id))
ticket = Ticket.query.get_or_404(ticket_id)
form = AdminPanelForm()
if form.validate_on_submit():
print("1")
if not ticket.date_solution:
print("2")
ticket.date_solution= datetime.now()
if not ticket.date_odpoved:
print("3")
if form.odpoved.data != ticket.odpoved:
print("4")
ticket.date_odpoved= datetime.now()
ticket.solution = form.solution.data
ticket.odpoved = form.odpoved.data
ticket.is_finished = True
db.session.commit()
flash("Ticket bol updatenutý", "success")
**return redirect(url_for('ticketmod.index_view'))**
elif request.method == 'GET':
form.solution.data = ticket.solution
form.odpoved.data = ticket.odpoved
return render_template("admin_ticket.html", form=form, ticket = ticket)
Now you can see that after succesful updating the ticket, user is redirected to Ticket model View where he came from, return redirect(url_for('ticketmod.index_view')) but without filters applied. I am looking for the solution, how can you store the url GET parameters (the filters) and then use them when redirecting back to ModelView. I tried function get_url() or request.referrer but I wasn´t succesful.
As I said in my original post, maybe I am missing something crucial in web architecture - if you have in mind some learning material I shoul be looking at : thanks for any advice.
Within the formatter method you can get a view's url including the applied filters/sorting criteria using the following:
_view_url = view.get_url('.index_view', **request.args)
Now pass this along to route request, either as a parameter or some other means. For example:
class TicketModelView(ModelView):
# blah blah
def _user_formatter(view, context, model, name):
if model.id:
# This is the current url of the view including filters
_view_url = view.get_url('.index_view', **request.args)
# Pass this as a parameter to your route
markupstring = "<a href= '%s'>%s</a>" % (url_for('ticket', ticket_id=model.id, return_url=_view_url), model.id)
return Markup(markupstring)
At the route you can now pull out the return_url from the request arg and add it as a hidden field in the form. Then in the post back retrieve the value from the form and redirect.
#app.route("/ticket/<int:ticket_id>/solution", methods = ['GET', 'POST'])
#login_required
def solution(ticket_id):
# Get the return_url from the request
_return_url = request.args.get('return_url'):
# Add the return_url to the form as a hidden field
form.return_url.data = _return_url
# blah blah
if form.validate_on_submit():
# get return value from form
_return_url = form.return_url.data
return redirect(_return_url) if _return_url else redirect(url_for('ticketmod.index_view'))

Change query parameter via select

I have a model Dish and a model Menu:
class MenuItem(models.Model):
dish_name=models.TextField(unique=False)
price=models.DecimalField(max_digits=5,decimal_places=2,blank=True)
main_ngredient=models.TextField(unique=False)
course=models.CharField(max_length=100)
menu=models.ForeignKey('Menu')
def __unicode__(self):
return name
class Menu(models.Model):
restaurant=models.TextField(unique=False)
year=models.IntegerField(unique=False)
location=models.TextField(unique=False)
status=models.CharField(unique=False,max_length=20)
NYPLid=models.IntegerField(unique=True)
def __unicode__(self):
return restaurant
def __period__(self):#adapted from http://stackoverflow.com/questions/2272149/round-to-5or-other-number-in-python
p=int(10*round(float(self.year)/10))
if p < self.year:
return "%s-%s"%(p,p+5)
else:
return "%s-%s"%(p-5,p)
period=property(__period__)
I have a view Search:
def search(request):
errors = []
form = SearchForm(request.GET)
if form.is_valid():
cd = form.cleaned_data
row = cd['row']
query = cd['query']
dish_row_dict = {"dish_name":'name__icontains=query',
"main_ingredient":"ingredient__icontains=query",
"course":"course__iexact=query"
}
menu_row_dict = {"year":'year__exact=query',
"period":'period__exact=query',
"location":'location__icontains=query',
"restaurant":"restaurant__icontains=query",
}
if row in dish_row_dict:
dishes = MenuItem.objects.filter(eval(dish_row_dict[row]))
elif row in menu_row_dict:
dishes = MenuItem.objects.filter(eval("menu__%s"%(menu_row_dict[row])))
return render_to_response("search_returns.html",{"dishes":dishes})
return render_to_response("search_page.html",{"form":form})
I have a form SearchForm:
class SearchForm(forms.Form):
row = forms.ChoiceField([("dish_name","Dish Name"),("year","Year"),
("period","Five-Year Period"),("location","Location"),
("main_ingredient","Main Ingredient"),("course","Course or Dish Type"),("restaurant","Restaurant"),])
query = forms.CharField())
I'd like users to be able to choose one of the select options, and then do a query based on their choice (e.g., search by dish name if they select "Dish Name".) They way I'm doing things now, with a dictionary+eval() isn't working (I know, I know, eval = bad, but I wasn't sure how else to do it!)
I feel like this isn't an exotic or uncommon thing, but I'll be damned if I can find anything about it online. I suspect the answer has something to do with MultiValueField or something like that, but I really don't understand how to make that work.
Any help would be greatly appreciated.
You can forget the =query and the eval() part and simply build a dict, and pass it as kwargs:
filter_keys = {
# menuitem queries
"dish_name":'name__icontains',
"main_ingredient": "ingredient__icontains",
"course": "course__iexact",
# menu queries
"year": 'menu__year__exact',
"period": 'menu__period__exact',
"location": 'menu__location__icontains',
"restaurant": "menu__restaurant__icontains",
}
...
if row in filter_keys:
dishes = MenuItem.objects.filter(**{filter_keys[row]: query})
The ** is a Python way of passing named parameters as a dict.

Prevent django admin from running SELECT COUNT(*) on the list form

Every time I use Admin to list the entries of a model, the Admin count the rows in the table. Worse yet, it seems to be doing so even when you are filtering your query.
For instance if I want to show only the models whose id is 123, 456, 789 I can do:
/admin/myapp/mymodel/?id__in=123,456,789
But the queries ran (among others) are:
SELECT COUNT(*) FROM `myapp_mymodel` WHERE `myapp_mymodel`.`id` IN (123, 456, 789) # okay
SELECT COUNT(*) FROM `myapp_mymodel` # why???
Which is killing mysql+innodb. It seems that the problem is partially acknowledged in this ticket, but my issue seems more specific since it counts all the rows even if it is not supposed to.
Is there a way to disable that global rows count?
Note: I am using django 1.2.7.
Django 1.8 lets you disable this by setting show_full_result_count = False.
https://docs.djangoproject.com/en/stable/ref/contrib/admin/#django.contrib.admin.ModelAdmin.show_full_result_count
Okay, I think I found a solution. As Peter suggested, the best approach is to work on the count property and it can be done by overriding it with custom query set (as seen in this post) that specialises the count with an approximate equivalent:
from django.db import connections, models
from django.db.models.query import QuerySet
class ApproxCountQuerySet(QuerySet):
"""Counting all rows is very expensive on large Innodb tables. This
is a replacement for QuerySet that returns an approximation if count()
is called with no additional constraints. In all other cases it should
behave exactly as QuerySet.
Only works with MySQL. Behaves normally for all other engines.
"""
def count(self):
# Code from django/db/models/query.py
if self._result_cache is not None and not self._iter:
return len(self._result_cache)
is_mysql = 'mysql' in connections[self.db].client.executable_name.lower()
query = self.query
if (is_mysql and not query.where and
query.high_mark is None and
query.low_mark == 0 and
not query.select and
not query.group_by and
not query.having and
not query.distinct):
# If query has no constraints, we would be simply doing
# "SELECT COUNT(*) FROM foo". Monkey patch so the we
# get an approximation instead.
cursor = connections[self.db].cursor()
cursor.execute("SHOW TABLE STATUS LIKE %s",
(self.model._meta.db_table,))
return cursor.fetchall()[0][4]
else:
return self.query.get_count(using=self.db)
Then in the admin:
class MyAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(MyAdmin, self).queryset(request)
return qs._clone(klass=ApproxCountQuerySet)
The approximate function could mess things up on page number 100000, but it is good enough for my case.
I found Nova's answer very helpful, but i use postgres. I modified it slightly to work for postgres with some slight alterations to handle table namespaces, and slightly different "detect postgres" logic.
Here's the pg version.
class ApproxCountPgQuerySet(models.query.QuerySet):
"""approximate unconstrained count(*) with reltuples from pg_class"""
def count(self):
if self._result_cache is not None and not self._iter:
return len(self._result_cache)
if hasattr(connections[self.db].client.connection, 'pg_version'):
query = self.query
if (not query.where and query.high_mark is None and query.low_mark == 0 and
not query.select and not query.group_by and not query.having and not query.distinct):
# If query has no constraints, we would be simply doing
# "SELECT COUNT(*) FROM foo". Monkey patch so the we get an approximation instead.
parts = [p.strip('"') for p in self.model._meta.db_table.split('.')]
cursor = connections[self.db].cursor()
if len(parts) == 1:
cursor.execute("select reltuples::bigint FROM pg_class WHERE relname = %s", parts)
else:
cursor.execute("select reltuples::bigint FROM pg_class c JOIN pg_namespace n on (c.relnamespace = n.oid) WHERE n.nspname = %s AND c.relname = %s", parts)
return cursor.fetchall()[0][0]
return self.query.get_count(using=self.db)
The Nova's solution (ApproxCountQuerySet) works great, however in newer versions of Django queryset method got replaced with get_queryset, so it now should be:
class MyAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
return qs._clone(klass=ApproxCountQuerySet)
If this is a serious problem you may have to take Drastic Actions™.
Looking at the code for a 1.3.1 install, I see that the admin code is using the paginator returned by get_paginator(). The default paginator class appears to be in django/core/paginator.py. That class has a private value called _count which is set in Paginator._get_count() (line 120 in my copy). This in turn is used to set a property of the Paginator class called count. I think that _get_count() is your target. Now the stage is set.
You have a couple of options:
Directly modify the source. I do not recommend this, but since you seem to be stuck at 1.2.7 you may find that it is the most expedient. Remember to document this change! Future maintainers (including possibly yourself) will thank you for the heads up.
Monkeypatch the class. This is better than direct modification because a) if you don't like the change you just comment out the monkeypatch, and b) it is more likely to work with future versions of Django. I have a monkeypatch going back over 4 years because they still have not fixed a bug in the template variable _resolve_lookup() code that doesn't recognize callables at the top level of evaluation, only at lower levels. Although the patch (which wraps the method of a class) was written against 0.97-pre, it still works at 1.3.1.
I did not spend the time to figure out exactly what changes you would have to make for your problem, but it might be along the lines of adding a _approx_count member to appropriate classes class META and then testing to see if that attr exists. If it does and is None then you do the sql.count() and set it. You might also need to reset it if you are on (or near) the last page of the list. Contact me if you need a little more help on this; my email is in my profile.
It is possible to change the default paginator used by the admin class. Here's one that caches the result for a short period of time: https://gist.github.com/e4c5/6852723
I managed to create a custom paginator that shows the current page numbe, a next button and a show full count link. It allows for the use of the original paginator if needed.
The trick used is to take per_page + 1 elements from db in order to see if we have more elements and then provide a fake count.
Let's say that we want the the third page and the page has 25 elements => We want object_list[50:75]. When calling Paginator.count the queryset will be evaluated for object_list[50:76](note that we take 75+1 elements) and then return either the count as 76 if we got 25+1 elements from db or 50 + the number of elements received if we didn't received 26 elements.
TL;DR:
I've created a mixin for the ModelAdmin:
from django.core.paginator import Paginator
from django.utils.functional import cached_property
class FastCountPaginator(Paginator):
"""A faster paginator implementation than the Paginator. Paginator is slow
mainly because QuerySet.count() is expensive on large queries.
The idea is to use the requested page to generate a 'fake' count. In
order to see if the page is the final one it queries n+1 elements
from db then reports the count as page_number * per_page + received_elements.
"""
use_fast_pagination = True
def __init__(self, page_number, *args, **kwargs):
self.page_number = page_number
super(FastCountPaginator, self).__init__(*args, **kwargs)
#cached_property
def count(self):
# Populate the object list when count is called. As this is a cached property,
# it will be called only once per instance
return self.populate_object_list()
def page(self, page_number):
"""Return a Page object for the given 1-based page number."""
page_number = self.validate_number(page_number)
return self._get_page(self.object_list, page_number, self)
def populate_object_list(self):
# converts queryset object_list to a list and return the number of elements until there
# the trick is to get per_page elements + 1 in order to see if the next page exists.
bottom = self.page_number * self.per_page
# get one more object than needed to see if we should show next page
top = bottom + self.per_page + 1
object_list = list(self.object_list[bottom:top])
# not the last page
if len(object_list) == self.per_page + 1:
object_list = object_list[:-1]
else:
top = bottom + len(object_list)
self.object_list = object_list
return top
class ModelAdminFastPaginationMixin:
show_full_result_count = False # prevents root_queryset.count() call
def changelist_view(self, request, extra_context=None):
# strip count_all query parameter from the request before it is processed
# this allows all links to be generated like this parameter was not present and without raising errors
request.GET = request.GET.copy()
request.GET.paginator_count_all = request.GET.pop('count_all', False)
return super().changelist_view(request, extra_context)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True):
# use the normal paginator if we want to count all the ads
if hasattr(request.GET, 'paginator_count_all') and request.GET.paginator_count_all:
return Paginator(queryset, per_page, orphans, allow_empty_first_page)
page = self._validate_page_number(request.GET.get('p', '0'))
return FastCountPaginator(page, queryset, per_page, orphans, allow_empty_first_page)
def _validate_page_number(self, number):
# taken from Paginator.validate_number and adjusted
try:
if isinstance(number, float) and not number.is_integer():
raise ValueError
number = int(number)
except (TypeError, ValueError):
return 0
if number < 1:
number = 0
return number
The pagination.html template:
{% if cl and cl.paginator and cl.paginator.use_fast_pagination %}
{# Fast paginator with only next button and show the total number of results#}
{% load admin_list %}
{% load i18n %}
{% load admin_templatetags %}
<p class="paginator">
{% if pagination_required %}
{% for i in page_range %}
{% if forloop.last %}
{% fast_paginator_number cl i 'Next' %}
{% else %}
{% fast_paginator_number cl i %}
{% endif %}
{% endfor %}
{% endif %}
{% show_count_all_link cl "showall" %}
</p>
{% else %}
{# use the default pagination template if we are not using the FastPaginator #}
{% include "admin/pagination.html" %}
{% endif %}
and templatetags used:
from django import template
from django.contrib.admin.views.main import PAGE_VAR
from django.utils.html import format_html
from django.utils.safestring import mark_safe
register = template.Library()
DOT = '.'
#register.simple_tag
def fast_paginator_number(cl, i, text_display=None):
"""Generate an individual page index link in a paginated list.
Allows to change the link text by setting text_display
"""
if i == DOT:
return '… '
elif i == cl.page_num:
return format_html('<span class="this-page">{}</span> ', i + 1)
else:
return format_html(
'<a href="{}"{}>{}</a> ',
cl.get_query_string({PAGE_VAR: i}),
mark_safe(' class="end"' if i == cl.paginator.num_pages - 1 else ''),
text_display if text_display else i + 1,
)
#register.simple_tag
def show_count_all_link(cl, css_class='', text_display='Show the total number of results'):
"""Generate a button that toggles between FastPaginator and the normal
Paginator."""
return format_html(
'<a href="{}"{}>{}</a> ',
cl.get_query_string({PAGE_VAR: cl.page_num, 'count_all': True}),
mark_safe(f' class="{css_class}"' if css_class else ''),
text_display,
)
You can use it this way:
class MyVeryLargeModelAdmin(ModelAdminFastPaginationMixin, admin.ModelAdmin):
# ...
Or an even simpler version that does not show the Next button and Show the total number of results :
from django.core.paginator import Paginator
from django.utils.functional import cached_property
class FastCountPaginator(Paginator):
"""A faster paginator implementation than the Paginator. Paginator is slow
mainly because QuerySet.count() is expensive on large queries.
The idea is to use the requested page to generate a 'fake' count. In
order to see if the page is the final one it queries n+1 elements
from db then reports the count as page_number * per_page + received_elements.
"""
use_fast_pagination = True
def __init__(self, page_number, *args, **kwargs):
self.page_number = page_number
super(FastCountPaginator, self).__init__(*args, **kwargs)
#cached_property
def count(self):
# Populate the object list when count is called. As this is a cached property,
# it will be called only once per instance
return self.populate_object_list()
def page(self, page_number):
"""Return a Page object for the given 1-based page number."""
page_number = self.validate_number(page_number)
return self._get_page(self.object_list, page_number, self)
def populate_object_list(self):
# converts queryset object_list to a list and return the number of elements until there
# the trick is to get per_page elements + 1 in order to see if the next page exists.
bottom = self.page_number * self.per_page
# get one more object than needed to see if we should show next page
top = bottom + self.per_page + 1
object_list = list(self.object_list[bottom:top])
# not the last page
if len(object_list) == self.per_page + 1:
object_list = object_list[:-1]
else:
top = bottom + len(object_list)
self.object_list = object_list
return top
class ModelAdminFastPaginationMixin:
show_full_result_count = False # prevents root_queryset.count() call
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True):
page = self._validate_page_number(request.GET.get('p', '0'))
return FastCountPaginator(page, queryset, per_page, orphans, allow_empty_first_page)
def _validate_page_number(self, number):
# taken from Paginator.validate_number and adjusted
try:
if isinstance(number, float) and not number.is_integer():
raise ValueError
number = int(number)
except (TypeError, ValueError):
return 0
if number < 1:
number = 0
return number

DJANGO simplejson

Good afternoon..i have a model with a class like this:
class Reportage:
def get_num(self):
end_date = self.date.end_date
start_date = self.date.start_date
duration = time.mktime(end_date.timetuple()) - time.mktime(start_date.timetuple())
delta_t = duration / 60
num = []
for t in range(0,duration,delta_t):
start = t + start_date
end = datetime.timedelta(0,t+delta_t) + start_date
n_num = self.get_num_in_interval(start,end)
num.append([t, n_num])
return num
I want to serialize with simplejson the array num [] in the views.py for passing in a second moment this array to a jquery script to plot it in a graph..
what's the code to serialize that array..?
I hope I was clear .. thanks in advance to all those who respond ..
Following #ninefingers' response. I think that your question is aimed on how to make that dumped json string available to a jQuery plugin.
# views.py
def my_view(request):
# do stuff
num = reportage_instance.get_num()
num_json = simplejson.dumps(num)
return render(request, 'template.html', {
'num_json': num_json,
})
In your template, you make available that json obj as a Javascript variable
# template.html
<html>
<body>
<script>
var NUM_JSON = {{num_json|safe}};
myScript.doSomething(NUM_JSON);
</script>
</body>
</html>
Now you can call regular JS with the NUM_JSON variable.
If you're looking to do this in a model, something like this would work:
# if this were a models.py file:
import simplejson
# other django imports:
class SomeModel(models.Model):
property = models.SomeField()...
def some_function(self):
num = []
# full num
simplejson.dumps(num)
That'll dump num to a string-representation of the json, which you can then return, or write to a file, and so on.
From a view you have a choice - but if your view is an ajax view returning some json for processing you might do this:
# views.py
# ...
def my_ajax_call(request, model_pk):
try:
mymodel = SomeModel.get(pk=model_pk)
except SomeModel.NotFoundException as e:
return HttpResonse("Unknown model", status=404)
else:
return HttpResponse(mymodel.some_function()) # returns simplejson.dumps(num)
This can then be used from a template in Javascript - the other answer shows you how you might approach that :)