pyramid_formalchemy assumptions about requests - python

I'm using pyramid_formalchemy 0.4.1...well I'm trying to use it.
When requests come in to my app I keep seeing pyramid_formalchemy making strange assumptions about what will be in the request object. My requests fail because in pyramid_formalchemy.views (starting at line: 58) the ModelView class has a constructor with the following code:
def __init__(self, context, request):
self.context = context
self.request = request
self.session = request.session_factory
self.fieldset_class = request.forms.FieldSet
self.grid_class = request.forms.Grid
The thing is my request object has a 'session' not a 'session_factory'. It also doesn't have 'forms'
Here is what I've done:
Create a RootFactory that extends pyramid_formalchemy.resources.Models
I call config.formalchemy_admin() passing it my RootFactory and my DBSession
I created an empty forms.py file.
What am I missing in my setup? Any ideas?
Thanks.

This stuff is configurable.
See the source
Not sure it's really documented..

Related

inject library dependencies into django model

I have a Django model that makes use of some libraries which I would like to be able to override. For instance, when testing I'd like to pass a mock instead of having my model tightly coupled. I can do this in python, but for the life of me I can't figure out how to do it with a Django model. Here's a simplified example not using Django:
import requests
class APIClient:
def __init__(self, **kwargs):
self.http_lib = kwargs.get("http_lib", requests)
def get_url(self, url):
return self.http_lib.get(url)
For regular use of this class I can still use requests but if I want to use a different library for some reason or if I want to test certain outcomes, I can invoke the class with client = APIClient(http_lib=MockRequests())
But how do I do that with a Django model? If I try to pass kwargs that aren't backed by a database field Django throws an error. Overriding __init__ is not considered a good practice either. Is there a way in Django to set and get a value that isn't backed by a database column?
Do you have a settings.TEST var? If so, you could make http_lib a function that returns the proper lib:
from django.conf import settings
def get_http_lib(mock=None):
if not mock:
return requests
return MockRequests()
class APIClient(Model):
def __init__(self, **kwargs):
# ...whatever...
#property
def some_column(self):
http_lib = get_http_lib(settings.TEST)
# ...etc...
Not ideal, but passable.
PRE-EDIT ANSWER (doesn't work):
What if you setattr subsequent to instantiating the Model?
# In model...
class APIClient(Model):
def __init__(self, **kwargs):
self.http_lib = requests
# ...etc...
# In tests...
client = APIClient()
setattr(client, 'http_lib', MockRequests())

Use WTForms QuerySelectField with Pyramid 1.7's db session

I use wtforms_sqlalchemy in my pyramid apps and define several QuerySelectFields. The query factory uses the imported DBSession object to make the query.
from wtforms.form import Form
from wtforms_sqlalchemy.fields import QuerySelectField
from myapp.models import DBSession, MyModel
def mymodel_choices():
choices = DBSession.query(MyModel)
return choices
class MyForm(Form):
mymod = QuerySelectField(u'Field', query_factory=mymodel_choices)
Pyramid 1.7 introduced a new SQLAlchemy scaffold which attaches the db session object to each request. Using the new scaffold mymodel_choices has to use request from my view to access the db session. The field doesn't have access to the request object though, and doesn't know to call the factory with it.
My idea was to update query_factory directly from the view but that doesn't seem to be a logical way to do it. How can I use QuerySelectField when the db session is part of the request object?
query_factory only specifies the default query to use, but QuerySelectField will prefer the query property if it is set. This is useful for Pyramid, which discourages interacting with threadlocal directly.
Change the factory to accept a db session. Set query to the result of calling your factory with the request's db session.
def mymodel_choices(session):
return session.query(MyModel)
f = MyForm(request.POST)
f.mymod.query = mymodel_choices(request.db_session)
Since this is a bit inconvenient, you can create a subclass of Form that takes the request, pulls out the appropriate form data, and calls each QuerySelectField's query factory with the request.
class PyramidForm(Form):
def __init__(self, request, **kwargs):
if 'formdata' not in kwargs and request.method == 'POST':
kwargs['formdata'] = request.POST
super().__init__(**kwargs)
for field in self:
if isinstance(field, QuerySelectField) and field.query_factory is not None and field.query is None:
field.query = field.query_factory(request.db_session)
class MyForm(PyramidForm):
...
f = MyForm(request)
You can try something like this (although it's not the cleanest solution)
from myapp.models import MyModel
from pyramid import threadlocal
def mymodel_choices(request=None):
request = request or threadlocal.get_current_request()
choices = request.DBSession.query(MyModel)
return choices
for more details please see: http://docs.pylonsproject.org/projects/pyramid/en/latest/api/threadlocal.html

Store objects at "request scope" in google app engine

I would like to store some information at the "request scope" when using google app engine (python). What I mean by this is that I would like to initialize some information when a request is first received, and then be able to access it from anywhere for the life of the request (and only from that request).
An example of this would be if I saved the current user's name at request scope after they were authenticated.
How would I go about doing this sort of thing?
Thanks!
A pattern used in app engine itself seems to be threading.local which you can grep for in the SDK code. Making os.environ request local is done like that in runtime/request_environment.py for example.
A rough example:
import threading
class _State(threading.local):
"""State keeps track of request info"""
user = None
_state = _State()
From elsewhere you could authenticate early on in handler code.
from state import _state
if authentication_passed:
_state.user = user
and provide convenience that can be used in other parts of your code
from state import _state
def get_authenticated_user():
user = _state.user
if not user:
raise AuthenticationError()
return user
You need something like this:-
class BaseHandler(webapp2.RequestHandler):
#A function which is useful in order to determine whether user is logged in
def initialize(self, *a, **kw):
#Do the authentication
self.username = username
class MainHandler(BaseHandler):
def get(self):
print self.username
Now if you inherit BaseHandler class all the request will first go through the initialize method of BaseHandler class and since in the BaseHandler class you are setting the username
and MainHandler inherits form BaseHandler you will have the self.username defined and all the request wil go through initialize method.

Python+Pyramid+Mako: What is the difference between the context in event, context in view and context in template?

I've been trying hard to understand this, but can't quite put a finger on a precise documentation about it. I am quite confused about the different meaning of context in this Python Pyramid+Mako setup.
Here is some code snippets (tell me if you need more context):
class Root(object):
request = None
def __init__(self, request):
self.request = request
#events.subscriber(events.BeforeRender)
def add_renderer_globals(event):
event[u'c'] = event[u'request'].tmpl_context
print u"add_renderer_globals(): request.tmpl_context={0}".format(event[u'request'].tmpl_context)
print u"add_renderer_globals(): context={0}".format(event[u'context'])
#view.view_config(route_name='login', request_method='GET', renderer='login.mako')
def login_get(context, request):
print u"login_get(): context={0}".format(context)
return {}
[...]
cfg = config.Configurator(root_factory=Root,
package=MyPKG,
settings=settings,
session_factory=pyramid_beaker.session_factory_from_settings(settings),
)
cfg.add_route(name='login', pattern='/login')
cfg.scan()
and in my mako template, just to have an example, I only have:
Mako template context=${context}
So I would make a request and I get the following outputs from console or browser:
login_get(): context=<MyPKG.Root object at 0x1523c90>
add_renderer_globals(): request.tmpl_context=<pyramid.request.TemplateContext object at 0x12fbc50>
add_renderer_globals(): context=<MyPKG.Root object at 0x1523c90>
Mako template context=<mako.runtime.Context object at 0x15a4950>
My question is: What are the differences, and what do you use them for? I'm also confused why semantically, I declared root_factory=MyPKG.Root and it becomes context=MyPKG.Root in my view and my subscriber.
Thanks for any hint to help me understand.
First, ignore request.tmpl_context. This is just a dictionary on the request object that you can add stuff to and is not normally used in Pyramid applications at all. It's a step-child from the Pylons merge.
There are two context objects when using Mako. The first (mako.runtime.Context) is supplied by Mako: http://docs.makotemplates.org/en/latest/runtime.html#context
Pyramid typically exposes the traversal context (MyPKG.Root) as context in your templates. However, Mako already has a variable using that name. :-( Thus, Pyramid's context is actually named _context.

Best way to integrate SqlAlchemy into a Django project

I changed my Django application to use SQLAlchemy, and it works now.
But I'm wondering where I should put these lines:
engine = sqlalchemy.create_engine(settings.DATABASE_URL)
Session = sqlalchemy.orm.sessionmaker(bind=engine)
session = Session()
The reason I'm asking is because I want to use SQLAlchemy at many place, and I don't think its correct/powerful/well-written to call this three lines everytime I need to use the database.
The place I will require SA is :
In my views, of course
In some middleware I wrote
In my models. Like in get_all_tags for a BlogPost Model.
What I think would be correct, is to get the session, by re-connecting to the database if the session is closed, or just returning the current, connected session if exists.
How can I use SQLAlchemy correctly with my Django apps?
Thanks for your help!
Note: I already followed this tutorial to implement SA into my Django application, but this one doesn't tell me exactly where to put those 3 lines (http://lethain.com/entry/2008/jul/23/replacing-django-s-orm-with-sqlalchemy/).
for the first two, engine and Session, you can put them in settings.py; they are, configuration, after all.
Actually creating a session requires slightly more care, since a session is essentially a 'transaction'. The simplest thing to do is to create it in each view function when needed, and commit them just before returning. If you'd like a little bit more magic than that, or if you want/need to use the session outside of the view function, you should instead define some middleware, something like
class MySQLAlchemySessionMiddleware(object):
def process_request(self, request):
request.db_session = settings.Session()
def process_response(self, request, response):
try:
session = request.db_session
except AttributeError:
return response
try:
session.commit()
return response
except:
session.rollback()
raise
def process_exception(self, request, exception):
try:
session = request.db_session
except AttributeError:
return
session.rollback()
Then, every view will have a db_session attribute in their requests, which they can use as they see fit, and anything that was added will get commited when the response is finished.
Don't forget to add the middleware to MIDDLEWARE_CLASSES

Categories