Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Pyramid, how can I use a different renderer based on contents of context?

I have 3 different product page layouts that I would like to display dependent on the information available about the products. Using traversal I have a class called ProductFinder that grabs all the information. For example the user goes to domain/green/small and ProductFinder will list all products from my DB that are green and small. This list is self.products in the ProductFinder class. In my __init__.py I have added the line:

config.add_view('app.views.products', name='')

In products.py I have:

from pyramid.view import view_config
@view_config(context='app.models.ProductFinder', renderer='productpage.mako')
def products(context, request):
    return dict(page=context)

Based on what's in context.products though I'd like to render a different mako. In Pylons I would have done something like:

def products(context, request):
    if len(context.products) == 1:
        return render("oneproduct.mako")
    elif len(context.product) == 2:
        return render("twoproducts.mako")

So how can I render a different template based on the contents of my context?

like image 373
jchysk Avatar asked Jul 01 '11 21:07

jchysk


2 Answers

I will start off by saying this sort of seems like something you want to take care of in your template.

However, you can influence which renderer is used as part of the view lookup in just about any way you want to. As you might already know you can use the same view handler for multiple views, you simply need to help Pyramid figure out which one to use.

For example:

from pyramid.view import view_config

def ProductLengthPredicate(length):
    def check_length(context, request):
        return len(context.products) == length
    return check_length

@view_config(context='app.models.ProductFinder', renderer='oneproduct.mako',
             custom_predicates=(ProductLengthPredicate(1),))
@view_config(context='app.models.ProductFinder', renderer='twoproducts.mako',
             custom_predicates=(ProductLengthPredicate(2),))
@view_config(context='app.models.ProductFinder', renderer='manyproducts.mako')
def products(context, request):
    return dict(page=context)

NB. Some people might be more interested in the render_to_response approach here because then they will not be relying on custom_predicates. But it is of course up to you!

@view_config(context='app.models.ProductFinder', renderer='manyproducts.mako')
def products(context, request)
    opts = dict(page=context)
    if len(context.products) == 1:
        return render_to_response('oneproduct.mako', opts, request)
    if len(context.products) == 2:
        return render_to_response('twoproducts.mako', opts, request)
    return opts

This works because Pyramid will ignore the renderers if your view returns a Response() which is exactly what render_to_response does.

like image 194
Michael Merickel Avatar answered Sep 21 '22 17:09

Michael Merickel


I'm not sure if it's the good way to go, but you could probably use request.override_renderer = 'oneproduct.mako'.

If it is just a different way of displaying your products depending on the quantity, you should do the decision in the template.

like image 40
Antoine Leclair Avatar answered Sep 24 '22 17:09

Antoine Leclair