Django/Python - Unwanted caching of instances in views.py - python

I'm having an issue with a page running on Django 2.1. My issue is that when a function is called from views.py to populate a template, an instance of a class seems to be cached. Every subsequent call to that function/every refresh of that page shows old data from the previous time that page/function was called.
The code in question:
projectroot/myapp/templates/myapp/bar.html
#this is bar.html
{{ MyTable.DataColumns }}
<br>
{{ MyTable.DataRows }}
projectroot/myapp/views.py
#this is a relevant snippet from views.py
#There isn't anything outside of the functions,
#with imports being the exception to this rule
import myownpackage.DataTable import DataTable
def list_page(request):
template = 'foo/bar.html'
connection = a_connection_here
query_results = connection.get_query_results(sql_query_here)
list_of_rows = [x for x in query_results]
dt = DataTable()
dt.DataColumns = [list_of_columns_here]
for each_row in list_of_rows:
dt.add(each_row)
return_dict = {"MyTable": dt}
return render(request, template, return_dict)
projectroot/myownpackage/DataTable.py
class DataTable:
DataColumns = []
DataRows = []
def add(self, data_row):
if len(self.DataColumns) != len(data_row):
raise IndexError("Target column count does not match DataTable's DataColumn count.")
else:
self.DataRows.append(data_row)
def remove(self, index):
self.DataRows.remove(index)
The first time this page is loaded, foo/bar.html appears to be just what I want. I can see the columns printed to the page, and the few rows in that table.
The problem is visible if you refresh the page. It's as if dt is being cached after the function has returned the render().
When you refresh the page, you'll see the columns, and the rows from the first request duplicated! If we refresh a third time, we'll see a third set of those same rows! This appending of the DataTable goes on for as many times as you refresh. Clearly, dt is being stored outside of this function after being instantiated within the function, and I'm not sure why, or how, this is happening.
NOTE: Only the rows are being added over and over again. The columns remain the same. This is because the columns are being set on the table, while the rows are being added.
Things I've tried:
After dt is assigned to that return_dict, I've tried dt = None and del dt. Neither of these worked, and the same results were shown when refreshing the page.
My questions to Stack Overflow:
Why isn't the instance of DataTable called dt being thrown away after the function returns?
If this (for whatever the reason may be) is normal, what can I do to destroy that instance of DataTable when I'm done with it?

It turns out, the issue was that the DataRows were static in the DataTable class. That class should look like this:
class DataTable:
def __init__(self):
self.DataColumns = []
self.DataRows = []

Related

Strange line in django_cron

I'm using this instruction http://django-cron.readthedocs.org/en/latest/installation.html and can't understand meaning of "a unique code" line.
from django_cron import CronJobBase, Schedule
class MyCronJob(CronJobBase):
RUN_EVERY_MINS = 120 # every 2 hours
schedule = Schedule(run_every_mins=RUN_EVERY_MINS)
code = 'my_app.my_cron_job' # a unique code
def do(self):
pass # do your thing here
Can anyone explain me what this line do?
code = 'my_app.my_cron_job' # a unique code
Looking at code here:
def make_log(self, *messages, **kwargs):
cron_log = self.cron_log
cron_job = getattr(self, 'cron_job', self.cron_job_class)
cron_log.code = cron_job.code
we can understand, that this "unique code" denote particular cron task. Every time your cron task is executed, CronJobLog instance is created with cron_log.code = cron_job.code.
So, it is possible to filter the logs, that belongs to particular task:
last_job = CronJobLog.objects.filter(code=cron_job.code).latest('start_time')
That is why it must be unique, to not mix logs from one cron task with another.
I suppose it has the same purpose as id, but this code has meaningful value.

Multiple questions with Object-Oriented Bokeh [OBSOLETE]

NOTE: This question concerns the "first generation" Bokeh server, which has been deprecated and removed for several years. Nothing in this question or its answers is relevant to any version of Bokeh >= 0.11
For detailed information about using the modern, supported Bokeh Server, see the Running a Bokeh Server chapter of the User's Guide.
I'm trying to understand Bokeh for an interactive app that I'm building. I'm looking at the Bokeh examples, and I see that most of the examples are written all in the global namespace, but the ones in the "app" subdirectory are written in a nice, object-oriented style, where the main class inhereits from a Property class like HBox.
This is going to be a mish-mash of questions because I don't think this way of programming Bokeh was very well-documented. The first thing I encountered was that the plot didn't draw unless I included extra_generated_classes.
What does extra_generated_classes do?
Secondly, it looks like the event loop setup_events is called on startup before create and subsequently every time the plot triggers an event.
Why does setup_events need to register callbacks each time an event is triggered? And why doesn't it wait for create to finish before attempting to register them the first time?
The last thing I'm unsure about is how to force a redraw of a Glyph here. The slider demo works for me, and I'm trying to do basically the same thing, except with a scatterplot instead of a line.
I set a pdb trace at the very end of my update_data, and I can guarantee that self.source matches self.plot.renderers[-1].data_source and that both of them have been tweaked from the start. However, self.plot itself doesn't change.
What is the object-oriented approach's equivalent to calling store_objects to update the plot?
I'm especially confused by this third one, because it doesn't look like the sliders_app example needs anything like that. For clarification, I'm trying to make a variable number of widgets/sliders, so this is what my code looks like:
class attributes:
extra_generated_classes = [['ScatterBias', 'ScatterBias', 'HBox']]
maxval = 100.0
inputs = Instance(bkw.VBoxForm)
outputs = Instance(bkw.VBoxForm)
plots = Dict(String, Instance(Plot))
source = Instance(ColumnDataSource)
cols = Dict(String, String)
widgets = Dict(String, Instance(bkw.Slider))
# unmodified source
df0 = Instance(ColumnDataSource)
initialize method
#classmethod
def create(cls):
obj = cls()
##############################
## load DataFrame
##############################
df = pd.read_csv('data/crime2013_tagged_clean.csv', index_col='full_name')
obj.cols = {'x': 'Robbery',
'y': 'Violent crime total',
'pop': 'Population'
}
cols = obj.cols
# only keep interested values
df2= df.ix[:, cols.values()]
# drop empty rows
df2.dropna(axis=0, inplace=True)
df0 = df2.copy()
df0.reset_index(inplace=True)
# keep copy of original data
obj.source = ColumnDataSource(df2)
obj.df0 = ColumnDataSource(df0)
##############################
## draw scatterplot
##############################
obj.plots = {
'robbery': scatter(x=cols['x'],
y=cols['y'],
source=obj.source,
x_axis_label=cols['x'],
y_axis_label=cols['y']),
'pop': scatter(x=cols['pop'],
y=cols['y'],
source=obj.source,
x_axis_label=cols['pop'],
y_axis_label=cols['y'],
title='%s by %s, Adjusted by by %s'%(cols['y'],
cols['pop'], cols['pop'])),
}
obj.update_data()
##############################
## draw inputs
##############################
# bokeh.plotting.scatter
## TODO: refactor so that any number of control variables are created
# automatically. This involves subsuming c['pop'] into c['ctrls'], which
# would be a dictionary mapping column names to their widget titles
pop_slider = obj.make_widget(bkw.Slider, dict(
start=-obj.maxval,
end=obj.maxval,
value=0,
step=1,
title='Population'),
cols['pop'])
##############################
## make layout
##############################
obj.inputs = bkw.VBoxForm(
children=[pop_slider]
)
obj.outputs = bkw.VBoxForm(
children=[obj.plots['robbery']]
)
obj.children.append(obj.inputs)
obj.children.append(obj.outputs)
return obj
update_data
def update_data(self):
"""Update y by the amount designated by each slider"""
logging.debug('update_data')
c = self.cols
## TODO:: make this check for bad input; especially with text boxes
betas = {
varname: getattr(widget, 'value')/self.maxval
for varname, widget in self.widgets.iteritems()
}
df0 = pd.DataFrame(self.df0.data)
adj_y = []
for ix, row in df0.iterrows():
## perform calculations and generate new y's
adj_y.append(self.debias(row))
self.source.data[c['y']] = adj_y
assert len(adj_y) == len(self.source.data[c['x']])
logging.debug('self.source["y"] now contains debiased data')
import pdb; pdb.set_trace()
Note that I am sure that the event handler gets setup and triggered correctly. I just don't know how to make the changed source data reflect in the scatterplot.
I'm searching for the same answers (lack of documentation makes it difficult).
In answer, to question #1, what is the utility of "extra_generated_classes":
tl;dr extra_generated_classes defines a modulename, classname, and parentname used in template generating js/html code, and extends the parent class passed into the app class (usually HBox or VBox in the examples).
Longer answer. Look at the source code in bokeh/server/utils/plugins.py, this is the code that is run on code passed to bokeh-server using the --script command line argument. At the end of plugins.py, you can see that extra_generated_classes is passed to the flask method render_template, which renders a Jinja2 template. Looking inside the template, oneobj.html, extra_generated_classes is an array of arrays of three things: modulename, classname, and parentname, which are passed into bokeh.server.generatejs:
{% block extra_scripts %}
{% for modulename, classname, parentname in extra_generated_classes %}
<script
src="{{ url_for('bokeh.server.generatejs', modulename=modulename, classname=classname, parentname=parentname) }}"
></script>
{% endfor %}
{% endblock %}
bokeh.server.generatejs is a Python code in bokeh/server/views/plugins.py, and only calls render_template for a template app.js, which you can find in bokeh/server/templates. This template takes the modulename, classname, and parentname, and basically creates js code which extends the parentname (e.g. HBox or VBox) to the classname (your app).

Web.py pass parameter to GET/POST function via ajax call on form submit

I have a main page that has a GET and a POST function. The POST function gets data from a search screen and should pass this information, via an ajax call, to the worldMarkers class. This is separate because it will be needed for other aspects of the application.
The goal of this, is to have a user press submit on index and during the POST call, it is able to limit the results retrieved. This logic exists in the worldMarkers class.
class index(object):
def GET(self):
# do things to generate the page
return html
def POST(self):
continents = web.input(search_continents=[])
countries = web.input(search_countries=[])
searchDict = {}
if continents['search_continents']:
searchDict['continents'] = continents['search_continents']
if countries['search_countries']:
searchDict['countries'] = countries['search_countries']
markers = worldMarkers()
# Yes, this just spits out the results, nothing fancy right now
return markers.GET()
#alternatively,
#return markers.GET(searchDict)
class worldMarkers(object):
def __init__(self, **kargs):
self.searchDict = None
if 'searchDict' in kargs:
self.searchDict = kargs['searchDict']
def GET(self):
print "SearchDict: %s" % (self.searchDict)
# No searchDict data exists
The first option, with no parameters to markers.GET() means that none of my search criteria has been passed. If I do markers.GET(searchDict), I receive this error:
<type 'exceptions.TypeError'> at /
GET() takes exactly 1 argument (2 given)
How can I pass my search parameters to the worldMarkers class?
It looks like you should actually create an instance of worldMarkers as follows in order for your searchDict to exist:
markers = worldMarkers(searchDict=searchDict)
Right now, you're creating it without the argument:
markers = worldMarkers()
and in that case, the condition if 'searchDict' in kargs is false and self.searchDict = kargs['searchDict'] is not run.
And, as #TyrantWave points out, your GET is not really prepared to take any arguments since it is only declared as def GET(self). See the last sample code of this section of the docs.

Python AppEngine, how to take parameters to another page

In my app, each page is each Python class. From page A, I want to take some data in this page and redirect to page B.
Does Google App Engine has some ways to do it ? (I don't want to use something like: global variable or cookie for this small work)
Thanks :)
You can compute the value you need in the first handler (AHandler), then redirect to the second handler (BHandler) passing that value as a GET parameter. Finally BHandler, reads that parameter and does something with it. Here is some code:
import urllib
class AHandler(webapp2.RequestHandler):
def get(self):
name = 'Some name'
redirect('b?%s' % urllib.urlencode({'name': name}))
class BHandler(webapp2.RequestHandler):
def get(self):
name = self.request.get('name')
# do something with name

Throw blank even-numbered/left pages

I am trying to typeset a large document using ReportLab and Python 2.7.
It has a number of sections (about 6 in a 1,000 page document) and I would like each to start on odd-numbered/right-hand page. I have no idea though whether the preceding page will be odd or even and so need the ability to optionally throw an additional blank page before a particular paragraph style (like you sometimes get in manuals where some pages are "intentionally left blank"). Can anyone suggest how this could be done, as the only conditional page break I can find works on the basis of the amount of text on the page not a page number.
I also need to make sure that the blank page is included in the PDF so that double-sided printing works.
If you can keep track of page numbers, then just add a PageBreak or canvas.showPage() command at the appropriate times.
If you're using the platypus engine within reportlab, you could try overriding the BaseDocTemplate class and using the afterPage and beforePage hooks to keep track of page numbers. Then you can use showPage() whenever you encounter an even page.
For example:
from reportlab.platypus import BaseDocTemplate
from reportlab.lib.pagesizes import A4
from reportlab.platypus import PageTemplate
class MyDocTemplate(BaseDocTemplate):
"""Override the BaseDocTemplate class to split even/odd pages"""
def __init__(self, *args, **kwargs):
BaseDocTemplate.__init__(self, *args, **kwargs)
self.__pageNum = 1
def afterPage(self):
"""Called after all flowables have been drawn on a page"""
# Increment pageNum since the page has been completed
self.__pageNum += 1
def beforePage(self):
"""Called before any flowables are drawn on a page"""
# If the page number is even, force a page break
if self.__pageNum % 2 == 0:
self.canv.showPage()
# Increment pageNum again since we've added a blank page
self.__pageNum += 1
Then you can use the new MyDocTemplate class to create your document:
if __name__ == "__main__":
doc = MyDocTemplate(
'filename.pdf',
pagesize=A4,
rightMargin=.3*inch,
leftMargin=.3*inch,
topMargin=.3*inch,
bottomMargin=.3*inch
)
# Your flowables go here
elements = []
# Your PageTemplates go here
doc.addPageTemplates([])
doc.build(elements)

Categories