Can you set session variables in MAKO files in Pyramid? - python

So I found this answer regarding setting session variables in a pyramid view file, and then later accessing it in a mako template. ( How to access session variable in Mako template and Pyramid? )
I wanted to know if you could do it the other way around. So instead of:
Pyramid view.py
def thisView(request):
session = request.session
session['selectedclientid'] = 'test' #selectedclient.id
session.save()
webpage.mako
${request.session['selectedclientid']}
Can I swap it so I can do this instead?
webpage.mako
${request.session['selectedclientid'] = '5'}
Pyramid view.py
def thisView(request):
someLogicOn(session['selectedclientid'])
So far I have been unsuccessful in making it work and I'm not sure if it's just due to a lack of understanding how to do it or if it's something that just can't be done. Any advice would be great!

In the typical rendering workflow, the view executes before the renderer. It's not clear how you are intending to correct for that. It's possible to do if you call render yourself within the view, I guess, so I'll show that.
webpage.mako:
<%
request.session['selectedClientId'] = '5'
%>
code:
def thisView(request):
response = render_to_response('webpage.mako', {}, request=request)
someLogicOn(request.session['selectedClientId'])
return response
This is logically a little backward though, so you might want to think twice about what you're doing.

Related

Exposing global data and functions in Pyramid and Jinja 2 templating

I have a base template for when a user is logged in, and on that base template, I need to add user specific options in a drop down menu. This drop down menu with options must be constant across all handlers, i.e., any time the base template is invoked (extended) with a child template.
Other than performing the necessary DB query, assigning the query results to a variable, and passing that variable to every handler (there are many), how can I consolidate this into one query and one variable, which gets passed directly to the base template? I am using jinja2 templates as well.
I would hate to do something so cumbersome in exchange for something far more simple and maintainable.
Any ideas? Thanks.
EDIT
So I still haven't found anything that's exactly what I'm looking for; however, I decided to at least make some headway in the interim. So, I made a custom decorator that takes a view's returned dict() and appends the appropriate data to it. For example:
def get_base_data(func):
def wrapper(request):
d = func(request)
user_id = request.user.id # used in query
contact_group_data = ContactGroups.query.filter(...criteria...).all()
d['contact_group_data'] = contact_group_data
return d
return wrapper
Now, I can at least decorate each method very concisely and simply by putting:
#view_config(...)
#get_base_data
def my_handler(request):
pass # rest of code...
This is one of most inobvious things in Pyramid and took a while to find for me, too.
You can modify the global template context in BeforeRender event.
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/hooks.html#using-the-before-render-event
Alternatively, you could use class based views, inherit all your views from one base view class which has get_base_data(), then the class instance is passed to the template context to all your views and then you could extract the data with {{ view.get_base_data }}.
http://ruslanspivak.com/2012/03/02/class-based-views-in-pyramid/
I vouch for the latter approach as it is more beautiful, predictable and easier to maintain engineering wise.

Get Mako template from within Pyramid app view

I'm currently using the Pyramid web framework and I have it configured with Mako templates. I know that I can render a template as a string from within a view method (Pyramid - Is it possible to render my mako template as a string within my view callable?), however, I was wondering if it is possible to get the actual template object from within a view and not just a function to render the template.
Looking through the Pyramid source code, in mako_templating.py I see that the default TemplateLookup class is overridden with a lookup method for Pyramid. Is there anyway to access this lookup object primarily so I can use the get_template function that is part of it?
Thanks for any direction on this issue.
This level of introspection is not officially supported by Pyramid's rendering API. That being said, here's a way to do it. This is completely undocumented, unsupported, private, etc, etc. Meaning, don't come complaining when this stops working.
from pyramid.mako_templating import IMakoLookup
lookup = request.registry.queryUtility(IMakoLookup, name='mako.')
tmpl = lookup.get_template('myapp:templates/foo.mako')
opts = {} # rendering context
result = tmpl.render_unicode(**opts)
This works for me:
from pyramid.renderers import render
sRenderedStuff = render('path/to/template.mak',dContext)
An example use case would be something like this:
sEmailHtml = render("email/welcome_message_html.mak",dContext)
With the following line in your pyramid settings file:
mako.directories = your_app:templates
The template is fetched from your_app/templates/email/welcome_message.html. All inheritance and include tags work just as they would for templates rendered to a view response.

Is there a way to know the variable name that URL Dispatcher pass to view?

i dont know if this is possible, but i will explain what i want try !
I made a Context Processor that will load some user information.
I need know, in this context processor, if there is a variable named "group" in the vars list that will be passed to my view, and if is, i will load up more things.
The processor only receive a REQUEST object, and i think with ONLY this is not possible.
But, with REQUEST_PATH (from request) i could make some magic (w/ urls.py) and find the exact view and variable that was choose by django. Is there a simple way to do this (or maybe ... a way ? :D ) ?
---- solution ----
The solution (using what yasar11732 say) is something like this:
x = resolve(request.META["PATH_INFO"])
if 'group_name' in x.kwargs
do_domething()
Thanks ! :)
see: resolve() It does exactly what are you trying to do. Be aware that this function throws an 404 exception if it doesn't find a match, so be ready to catch it.
Could you just add this in selectively on a per-view basis? Then you could do something like this:
def group_processor(request):
# ...
def some_view(request, user, group=None):
# ...
processors = [group_processor] if group else []
context = RequestContext(request, {}, processors)
return render_to_response("my_template.html", context_instance=context)

Is it possible to check whether a context variable is already set in a view within a custom context processor definition?

The issue is that in some views, I am manually getting a context variable (let's say "G") of interest since I use it to find other information in that particular view (i.e.views A,B,C), but in other views (i.e. X,Y,Z), I need to get that particular context variable since this context is to be available in every single view in my project (since my base template uses the context variable). The issue with using a custom context processor is that I believe it will make an additional and IDENTICAL DB call in views (A,B,C) since those views are already getting that context variable since it's needed to get other data in the view. What I was thinking was maybe I could implement a context processor that checks whether that specific context variable is set for a given request. Is this possible? Is there an easier solution? The code below may clarify the issue for some people.
Thank you for any advice!
def viewA(request):
g=G.objects.get(user=request.user)
posts = Post.objects.filter(g=g)
return direct_to_template(request,'something.html',{'G':g, 'posts':posts})
def viewX(request):
stuff = Albums.objects.get(user=request.user)
return direct_to_template(request,'something2.html',{'stuff':stuff})
def my_context_processor(request): #redundant in case of viewA (hits db again?)
return {'G':G.objects.get(user=request.user)}
def ideal_processor(request):
#check context vars to see if G is already in there
#if it is, return {}, else, return {'G':G.objects.get(user=request.user)}
def always_G(request):
if not hasattr(request, 'G'):
{'G':G.objects.get(user=request.user)}
I just made middleware that sets the variabel G to request.G since I need it on virtually every request anyway. i.e.:
class GuildMiddleware(object):
def process_request(self, request):
request.G = figure_out_what_G_is()
return None
Now you can use request.G anywhere in your views (and templates if you're using direct_to_template, RequestContext, etc.).

How do I submit a form given only the HTML source?

I would like to be able to submit a form in an HTML source (string). In other words I need at least the ability to generate POST parameters from a string containing HTML source of the form. This is needed in unit tests for a Django project. I would like a solution that possibly;
Uses only standard Python library and Django.
Allows parameter generation from a specific form if there is more than one form present.
Allows me to change the values before submission.
A solution that returns a (Django) form instance from a given form class is best. Because it would allow me to use validation. Ideally it would consume the source (which is a string), a form class, and optionally a form name and return the instance as it was before rendering.
NOTE: I am aware this is not an easy task, and probably the gains would hardly justify the effort needed. But I am just curious about how this can be done, in a practical and reliable way. If possible.
You should re-read the documentation about Django's testing framework, specifically the part about testing views (and forms) with the test client.
The test client acts as a simple web browser, and lets you make GET and POST requests to your Django views. You can read the response HTML or get the same Context object the template received. Your Context object should contain the actual forms.Form instance you're looking for.
As an example, if your view at the URL /form/ passes the context {'myform': forms.Form()} to the template, you could get to it this way:
from django.test.client import Client
c = Client()
# request the web page:
response = c.get('/form/')
# get the Form object:
form = response.context['myform']
form_data = form.cleaned_data
my_form_data = {} # put your filled-out data in here...
form_data.update(my_form_data)
# submit the form back to the web page:
new_form = forms.Form(form_data)
if new_form.is_valid():
c.post('/form/', new_form.cleaned_data)
Hopefully that accomplishes what you want, without having to mess with parsing HTML.
Edit: After I re-read the Django docs about Forms, it turns out that forms are immutable. That's okay, though, just create a new Form instance and submit that; I've changed my code example to match this.
Since the Django test framework does this, I'm not sure what you're asking.
Do you want to test a Django app that has a form?
In which case, you need to do an initial GET
followed by the resulting POST
Do you want to write (and test) a Django app that submits a form to another site?
Here's how we test Django apps with forms.
class Test_HTML_Change_User( django.test.TestCase ):
fixtures = [ 'auth.json', 'someApp.json' ]
def test_chg_user_1( self ):
self.client.login( username='this', password='this' )
response= self.client.get( "/support/html/user/2/change/" )
self.assertEquals( 200, response.status_code )
self.assertTemplateUsed( response, "someApp/user.html")
def test_chg_user( self ):
self.client.login( username='this', password='this' )
# The truly fussy would redo the test_chg_user_1 test here
response= self.client.post(
"/support/html/user/2/change/",
{'web_services': 'P',
'username':'olduser',
'first_name':'asdf',
'last_name':'asdf',
'email':'asdf#asdf.com',
'password1':'passw0rd',
'password2':'passw0rd',} )
self.assertRedirects(response, "/support/html/user/2/" )
response= self.client.get( "/support/html/user/2/" )
self.assertContains( response, "<h2>Users: Details for", status_code=200 )
self.assertContains( response, "olduser" )
self.assertTemplateUsed( response, "someApp/user_detail.html")
Note - we don't parse the HTML in detail. If it has the right template and has the right response string, it has to be right.
It is simple... and hard at the same time.
Disclaimer: I don't know much about Python and nothing at all about Django... So I give general, language agnostic advices...
If one of the above advices doesn't work for you, you might want to do it manually:
Load the page with an HTML parser, list the forms.
If the method attribute is POST (case insensitive), get the action attribute to get the URL of the request (can be relative).
In the form, get all input and select tags. The name (or id if no name) attributes are the keys of the request parameters. The value attributes (empty if absent) are the corresponding values.
For select, the value is the one of the selected option or the displayed text is no value attribute.
These names and values must be URL encoded in GET requests, but not in POST ones.
HTH.
Check out mechanize or it's wrapper twill. I think it's ClientForm module will work for you.

Categories