Last active
December 14, 2015 17:58
-
-
Save shazow/5125541 to your computer and use it in GitHub Desktop.
My Pyramid class-based view base class.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A sample view from my upcoming meta-framework. | |
# You probably won't have things like `request.features` or `api` or `expose_api` etc. Coming soon. | |
@expose_api('account.create') | |
def account_create(request): | |
if request.features.get('invite_required'): | |
raise APIControllerError("Method not permitted: %s" % account_create.exposed_name) | |
email, password, password_confirm = get_many(request.params, required=['email'], optional=['password', 'password_confirm']) | |
if password != password_confirm: | |
raise APIControllerError('Password confirmation does not match.') | |
if password and len(password) < 3: | |
raise APIControllerError('Please choose a longer password.') | |
return {'user': api.account.create(email=email, password=password)} | |
class AccountController(Controller): | |
def create(self): | |
if self.request.features.get('invite_required'): | |
raise HTTPNotFound() | |
self.title = 'Create an account' | |
user_id = api.account.get_user_id(self.request) | |
if user_id: | |
return self._redirect(location=self.next) | |
method = self.request.params.get('method') | |
if not method: | |
# Default behaviour, no form submitted. | |
return self._render('account/create.mako') | |
try: | |
# Form submitted, delegate the self.request to the API controller. | |
r = api_controller(self.request) | |
except APIControllerError, e: | |
# API Controller rejected the self.request, re-render the form with the error. | |
self.session.flash(e.message) | |
return self._render('account/create.mako') | |
# Submission processed successfully, login and redirect to the next page. | |
api.account.login_user_id(self.request, r['user'].id) | |
self.session.flash('Welcome.') | |
return self._redirect(location=self.next) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pyramid.httpexceptions import HTTPSeeOther | |
from pyramid.renderers import render_to_response, render | |
class Context(dict): | |
__getattr__ = dict.__getitem__ | |
__setattr__ = dict.__setitem__ | |
class Controller(object): | |
""" | |
This base class can be used in two ways: | |
1. You can use it as a handler base class as defined in pyramid_handlers. | |
2. You can use it as a singular route handler if you provide a __call__ | |
definition with the route logic which returns a response. | |
""" | |
DEFAULT_NEXT = '/' | |
title = None | |
def __init__(self, request): | |
self.request = request | |
self.session = request.session | |
self.context = self.c = Context() | |
self.previous_url = self.request.referer | |
self.current_path = self.request.path_qs | |
self.next = request.params.get('next') | |
# Prevent cross-site forwards (possible exploit vector). | |
if not self.next or self.next.startswith('//') or '://' in self.next: # Can we do this better? | |
self.next = self.DEFAULT_NEXT | |
def _default_render_values(self): | |
return { | |
'c': self.context, | |
'features': self.request.features, | |
'request': self.request, | |
'session': self.session, | |
'settings': self.request.registry.settings, | |
'title': self.title, | |
'is_logged_in': 'user_id' in self.session, | |
'current_path': self.current_path, | |
'previous_url': self.previous_url, | |
'next': self.next, | |
} | |
def _get_render_values(self, extra_values=None): | |
value = self._default_render_values() | |
if extra_values: | |
value.update(extra_values) | |
return value | |
def _render(self, renderer_name, extra_values=None, package=None): | |
value = self._get_render_values(extra_values=extra_values) | |
return render_to_response(renderer_name, value=value, request=self.request, package=package) | |
def _render_template(self, renderer_name, extra_values=None, package=None): | |
value = self._get_render_values(extra_values=extra_values) | |
return render(renderer_name, value=value, request=self.request, package=package) | |
def _redirect(self, *args, **kw): | |
"Shortcut for returning pyramid.exceptions.HTTPFound" | |
return HTTPSeeOther(*args, **kw) | |
def _respond(self): | |
"Override this to implement the view's response behavior." | |
raise NotImplemented('View response not implemented: %s' % self.__class__.__name__) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment