Django, session attr - python

I am trying to use session to pass some data from one page to another page.
Here is the code i wrote in ajax.py.
def save_cookie(request, query):
request.session['query'] = query
But when i call this dajaxice function.An error will occurred. As we all know that when we try to use dajaxice in html page, the error msg always is "sth goes wrong".
I tried to debug save_cookie, but the mock request object i created has no session attr. However, if i do request.session="blah", it worked. If I directly use save_cookie(request,query). It will pop up the error msg that request object has no attr seesion...
The code is right straight forward. I didn't see any mistake in it. Does anyone know the cause?

Never used dajaxice / dajax so I can't really help here. Just a few points:
did you enable (and properly configue) the session support ? https://docs.djangoproject.com/en/1.3/topics/http/sessions/
you can use the logging module (or a plain "print" statement but then you won't have the whole traceback) to trace the exception, ie :
def save_cookie(request, query):
try:
request.session['query'] = query
except Exception, e:
print e
raise
The output of the print statement should now appear in the shell you started the dev server from (assuming you're working with the dev server... you ARE workin with the dev server, aren't you ?)
still using the dev server, you can use pdb to switch to interactive debugging:
def save_cookie(request, query):
import pdb; pdb.set_trace()
request.session['query'] = query
then try to access the url in your browser, switch back to your shell and you're in a pdb session where you can inspect the request and (if there's one) request.session object etc.
NB : don't do this if running behind Apache or any other web server - only with the builtin dev server.
"request.session='blah'" will create the "session" attribute on the "request" object if it doesn't exist (and possibly replace the real "session" object if it already existed), so it's neither a valid test nor something sensible to do
My 2 cents...

Disclaimer: I don't know anything about dajaxice.
The following will work on a mock request object:
def save_cookie(request, query):
if not hasattr(request, 'session'):
request.session = dict()
request.session['query'] = query

Related

Mailchimp python wrapper gives error - no session

I'm trying to implement the mailchimp python API in a django project similar, following their example on github. I was trying to make a connection in a class based view however when I load up the view I get the notice
Attribute Error at\
'module' object has no attribute 'session'
It's set up exactly like their example and the error occurs where I define
m = get_mailchimp_api()
I opened up the mailchimp.py file in my site packages after following the traceback and saw the following:
import requests
class Mailchimp(object):
root = 'https://api.mailchimp.com/2.0/'
def __init__(self, apikey=None, debug=False):
'''Initialize the API client
Args:
apikey (str|None): provide your MailChimp API key. If this is left as None, we will attempt to get the API key from the following locations::
- MAILCHIMP_APIKEY in the environment vars
- ~/.mailchimp.key for the user executing the script
- /etc/mailchimp.key
debug (bool): set to True to log all the request and response information to the "mailchimp" logger at the INFO level. When set to false, it will log at the DEBUG level. By default it will write log entries to STDERR
'''
self.session = requests.session()
The traceback ends at the self.session = requests.session() line.
This is my view where I am trying to call Mailchimp
from app.utils import get_mailchimp_api
import mailchimp
from django.views.generic import TemplateView
class HomeView(TemplateView):
template_name = 'home.html'
# print requests -- this is undefined
m = get_mailchimp_api()
Is it because the CBV doesn't have a request parameter? In the github example they show the connection being made in a function based view where the function takes a requests. If that's the case, how can I pass the response into the CBV? This is the exact example Mailchimp gives on github:
def index(request):
try:
m = get_mailchimp_api()
lists = m.lists.list()
except mailchimp.Error, e:
messages.error(request, 'An error occurred: %s - %s' % (e.__class__, e))
return redirect('/')
Requests doesn't have a session() method...but id does have a Session() object.
Sounds like a bug in the wrapper.
Requests aliases Session() with session(), so that's probably not the issue. It almost sounds like there's something up either with your get_mailchimp_api() method or something is weird with the imports. Other stackoverflow questions about similar error messages seem to come from mutual imports, typos, or other such things.
Presumably your app.utils module is importing mailchimp already, like MailChimp's does? If not, I'd try that. If so, maybe remove your import mailchimp from this file.

Reraising an exception as an HTTP error in Pyramid

I have a web app in python Pyramid which calls various other code in python which may raise an exception.
Instead of the user receiving a "500 Internal Error", I'd like them to get a more specific error, for instance if MyException is thrown, show a 503 Error. I tried to do this:
#view_config(context=MyException, permission='view')
def custom_exc(exc, request):
raise HTTPServiceUnavailable(exc.message)
However, that fails because it is for some reason unauthorized:
HTTPForbidden: Unauthorized: custom_exc failed permission check
My ACL is as follows:
class RootFactory(object):
__acl__ = [
(Allow, 'admin', ('view',))
]
I am connected with the user admin and it works perfectly for other views.
Does anyone know how to solve this or else how to "chain" exceptions in Pyramid in a different way?
Learn from a customized version of famous ToDoPyramid example application. This way I translate an internal technical event, a database exception, into a meaningful application specific message within custom exception view code. Some guys call this a layer of abstraction or information hiding.
Do not protect these exception views with permissions, since you should protect code that does stuff and CAN raise exceptions.
from sqlalchemy.exc import OperationalError as SqlAlchemyOperationalError
#view_config(context=SqlAlchemyOperationalError)
def failed_sqlalchemy(exception, request):
"""catch missing database, logout and redirect to homepage, add flash message with error
implementation inspired by pylons group message
https://groups.google.com/d/msg/pylons-discuss/BUtbPrXizP4/0JhqB2MuoL4J
"""
msg = 'There was an error connecting to database'
request.session.flash(msg, queue='error')
headers = forget(request)
# Send the user back home, everything else is protected
return HTTPFound(request.route_url('home'), headers=headers)

How to disable Django Internal function cache?

I'm making some Django projects using Redis as Backend Cache[1], but I can't be sure that the Redis Server will be On all the time, then I'm trying to use Redis "if" it's available otherwise use some other Backend like LocMem and so on.
The Redis Backend that I'm using[1] is full compatible so I can use Django Decorations.
I was think to create a function to be called like that:
from django.views.decorators.cache import cache_page
from utils import PingBackend
from time import time
#cache_page(60, cache=PingBackend(time()))
def index(request):
artigos = Artigo.objects.filter(ativo=1)
return render_to_response('index.html', {'artigos':artigos}, RequestContext(request))
The problem is that Django (Internals I guess) Caches the response of PingBackend() and call it just the first time, even if I drop the RedisServer Django tells that the ping process was successfully.
It occurs even with DEBUG=True and 'default' CacheBackend to dummy.
def PingBackend(time):
print time
response = None
try:
con = StrictRedis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=0)
# Execute some action
con.ping()
# If not give an exception, use redis
response = 'redis'
except:
response = 'default' #dummy
return last_response
I'm passing time() just to create some differentiation as a try solve the cache problm.
The big picture is that the function PingBackend() aren't executing for each request, just for the first the I can't monitor the Redis Server.
Thank you!
[1] - https://github.com/niwibe/django-redis
This is not about Django internals, this is about how decorators work. When you define your view like this:
#cache_page(60, cache=PingBackend(time()))
def index(request):
blah blah
it is exactly equivalent to this:
def index(request):
blah blah
index = cache_page(60, cache=PingBackend(time()))(index)
You are invoking cache_page only one, passing it a cache argument that you got by invoking PingBackend once. It isn't even executing just for the first request, it is executing once when the view function is defined.
You should write your own cache backend that uses Redis if it's available, or something else if it is not.

In Pyramid, how to check if view is static in NewRequest event handler?

I have a NewRequest event handler (subscriber) in Pyramid which looks like this:
#subscriber(NewRequest)
def new_request_subscriber(event):
request = event.request
print('Opening DB conn')
// Open the DB
request.db = my_connect_to_db()
request.add_finished_callback(close_db_connection)
However, I have observed that a connection to the DB is opened even if the request goes to a static asset, which is obviously unnecessary. Is there a way, from the NewRequest handler, to check if the request is bound for a static asset? I have tried comparing the view_name to my static view's name, but apparently the view_name attribute is not available at this early stage of processing the request.
If anyone has any interesting ideas about this, please let me know!
The brute force way is to compare the request.path variable to your static view's root, a la request.path.startswith('/static/').
The method I like the best and use in my own apps is to add a property to the request object called db that is lazily evaluated upon access. So while you may add it to the request, it doesn't do anything until it is accessed.
import types
def get_db_connection(request):
if not hasattr(request, '_db'):
request._db = my_connect_to_db()
request.add_finished_callback(close_db_connection)
return request._db
def new_request_subscriber(event):
request = event.request
request.db = types.MethodType(get_db_connection, request)
Later in your code you can access request.db() to get the connection. Unfortunately it's not possible to add a property to an object at runtime (afaik), so you can't set it up so that request.db gives you what you want. You can get this behavior without using a subscriber by the cookbook entry where you subclass Request and add your own lazy property via Pyramid's #reify decorator.
def _connection(request):
print "******Create connection***"
#conn = request.registry.dbsession()
conn = MySQLdb.connect("localhost", "DB_Login_Name", "DB_Password", "data_base_name")
def cleanup(_):
conn.close()
request.add_finished_callback(cleanup)
return conn
#subscriber(NewRequest)
def new_request_subscriber(event):
print "new_request_subscriber"
request = event.request
request.set_property(_connection, "db", reify = True)
try this one, I reference fallow web page
http://pyramid.readthedocs.org/en/1.3-branch/api/request.html
"set_property" section, it works for me.

Python or Django: handle raised exception from imported library without internal server error

I've created a library that connects to some remote JSON api. I have a Django application that will render a internal server error, if my library fails connecting to the resource (504 error). Here is a hypothetical example that kind of shows the layout of my library's code.
mymodule.py
...
class Error(Exception):
"""class placeholder for errors"""
class theObject(object):
#classmethod
def get(self, params = {}):
url = 'http://somewhere.com/collection.json%s' % (urlencode(params))
try:
response = unicode(urlopen(url).read(), 'utf8').decode()
dictionary = json.loads(response)
result = ApiObject(dictionary)
return result
except HTTPError, e:
raise Error(e.read())
except (ValueError, KeyError), e:
raise Error('Invalid Response')
class Person(theObject):
#classmethod
def get_person(cls, person_id):
params = {'id':person_id)
result = super(Stuff, cls).get(params)
return result
view.py
import mymodule
...
remote_result = module.Person.get_person(person_id=person)
...
Is there a recommended way to alert the user that the resource is too busy? This would be better than rendering an internal server error from my current ajax requests.
Thanks!!
Figured my problem out. I feel stupid, because the solution is so simple. Hopefully, this will help someone out in the future who runs into the same issue. If a HTTP connection fails on an imported library, you can avoid rendering a server error page and produce a friendly notification for the client.
All it requires is that you find the class in the imported library that handles the errors. In this case, it is named "Error."
import mymodule
try:
[do a bunch of things...]
except mymodule.Error:
error = "Remote servers appear to be busy. Please try again."
return HttpResponse(error)
You can and probably should customize it to handle exceptions specific to the raised HTTPError.
Cheers!

Categories

Resources