Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ Flask Kit Changelog

Here you can see the Flask Kit evolution.

Version 0.5
------------
- Django style Url Routing added to AppFactory - but with no regexp!
- see base/urls.py for example required routes definition structure
- added template-filter registration to AppFactory - define in settings just like extensions or context-processors
- added baseviews file, contains BaseView and ModelView classes, subclass your views from here

Version 0.4
-----------
Expand Down
38 changes: 38 additions & 0 deletions base/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from flask import Markup
try:
from markdown2 import markdown as md2
except ImportError:
from markdown import markdown as md2
# Jinja

def date(value):
"""Formats datetime object to a yyyy-mm-dd string."""
return value.strftime('%Y-%m-%d')


def date_pretty(value):
"""Formats datetime object to a Month dd, yyyy string."""
return value.strftime('%B %d, %Y')


def datetime(value):
"""Formats datetime object to a mm-dd-yyyy hh:mm string."""
return value.strftime('%m-%d-%Y %H:%M')


def pluralize(value, one='', many='s'):
"""Returns the plural suffix when needed."""
return one if abs(value) == 1 else many


def month_name(value):
"""Return month name for a month number."""
from calendar import month_name
return month_name[value]


def markdown(value):
"""Convert plain text to HTML."""
extras = ['fenced-code-blocks', 'wiki-tables']
return Markup(md2(value, extras=extras))

5 changes: 3 additions & 2 deletions base/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
:license: BSD, see LICENSE for more details.
"""

from flask.ext.wtf import Form, TextField, Required, PasswordField
from wtforms.validators import Email
from flask.ext.wtf import Form
from wtforms.fields import TextField, PasswordField
from wtforms.validators import Email, DataRequired as Required


class LoginForm(Form):
Expand Down
11 changes: 11 additions & 0 deletions base/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from . import base
from .views import FrontView,LoginView,logout

routes = [
((base),
('',FrontView.as_view('front_page')),
('login',LoginView.as_view('login')),
('logout',logout),
)
]

3 changes: 0 additions & 3 deletions base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class FrontView(MethodView):
def get(self):
return render_template('base/main.html')

base.add_url_rule('', view_func=FrontView.as_view('front_page'))


class LoginView(MethodView):
Expand Down Expand Up @@ -53,7 +52,6 @@ def post(self):

return redirect(request.args.get('next') or url_for('base.front_page'))

base.add_url_rule('login', view_func=LoginView.as_view('login'))


login_manager.login_view = 'base.login'
Expand All @@ -70,4 +68,3 @@ def logout():
logout_user()
return redirect(url_for('base.front_page'))

base.add_url_rule('logout', view_func=logout, methods=['POST'])
80 changes: 80 additions & 0 deletions baseviews.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from flask.views import MethodView
from flask.templating import render_template
from flask.helpers import url_for
from flask import redirect, flash
from wtforms.form import FormMeta

class BaseView(MethodView):
_template = None
_form = None
_context = {}
_form_obj = None
_obj_id = None
_form_args = {}

def render(self,**kwargs):
if self._template is None:
return NotImplemented
if kwargs:
self._context.update(kwargs)
if self._form is not None:

if type(self._form) == FormMeta:
if self._form_obj is not None:
self._context['form'] = self._form(obj=self._form_obj,**self._form_args)
else:
self._context['form'] = self._form(**self._form_args)
if self._obj_id is not None:
self._context['obj_id'] = self._obj_id
else:
self._context['form'] = self._form
choices = self._context.get('choices')
if choices:
self._context['form'].template.template.choices = choices
for f,v in self._form_args.items():
self._form.__dict__[f].data = v
return render_template(self._template,**self._context)

def redirect(self,endpoint,**kwargs):
return redirect(url_for(endpoint,**kwargs))

def flash(self,*args,**kwargs):
flash(*args,**kwargs)

class ModelView(BaseView):
_model = None

def render(self,**kwargs):
if self._model is not None:
if 'model_id' in kwargs:
model_id = kwargs.pop('model_id')
elif self._model.__name__ + '_id' in kwargs:
model_id = kwargs.pop(self._model.__name__+'_id')
else:
model_id = None
if model_id is not None:
self._context['object'] = self.get_by_id(model_id)
else:
self._context['object'] = self._model()
self.context['model'] = self._model
return super(ModelView,self).render(**kwargs)

def add(self,**kwargs):
tmp = self._model(**kwargs)
tmp.save()

def update(self,model_id,**kwargs):
tmp = self._model.query.filter_by(self._model.id==model_id).first()
if 'return' in kwargs:
if kwargs.pop('return',None):
rtn = True
else:
rtn = False
for k in kwargs.keys():
tmp.__dict__[k] = kwargs[k]
tmp.save()
if rtn: return tmp

def get_by_id(self,model_id):
tmp = self._model.get_by_id(model_id)
return tmp
71 changes: 61 additions & 10 deletions helpers.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
# -*- coding: utf-8 -*-

"""
helpers
~~~~~~~

Implements useful helpers.

:copyright: (c) 2012 by Roman Semirook.
main.py - where the magic happens
~~~~~~~~
:license: BSD, see LICENSE for more details.
"""

import os
from flask import Flask
from werkzeug.utils import import_string

class NoRouteModuleException(Exception):
pass

class NoContextProcessorException(Exception):
class NoTemplateFilterException(Exception):
pass

class NoContextProcessorException(Exception):
pass

class NoBlueprintException(Exception):
pass


class NoExtensionException(Exception):
pass


class AppFactory(object):

def __init__(self, config, envvar='PROJECT_SETTINGS', bind_db_object=True):
Expand All @@ -41,7 +39,9 @@ def get_app(self, app_module_name, **kwargs):

self._bind_extensions()
self._register_blueprints()
self._register_routes()
self._register_context_processors()
self._register_template_filters()

return self.app

Expand All @@ -52,6 +52,8 @@ def _get_imported_stuff_by_path(self, path):
return module, object_name

def _bind_extensions(self):
if self.app.config.get('VERBOSE',False):
print 'binding extensions'
for ext_path in self.app.config.get('EXTENSIONS', []):
module, e_name = self._get_imported_stuff_by_path(ext_path)
if not hasattr(module, e_name):
Expand All @@ -62,7 +64,19 @@ def _bind_extensions(self):
else:
ext(self.app)

def _register_template_filters(self):
if self.app.config.get('VERBOSE',False):
print 'registering template filters'
for filter_path in self.app.config.get('TEMPLATE_FILTERS', []):
module, f_name = self._get_imported_stuff_by_path(filter_path)
if hasattr(module, f_name):
self.app.jinja_env.filters[f_name] = getattr(module, f_name)
else:
raise NoTemplateFilterException('No {f_name} template filter found'.format(f_name=f_name))

def _register_context_processors(self):
if self.app.config.get('VERBOSE',False):
print 'registering template context processors'
for processor_path in self.app.config.get('CONTEXT_PROCESSORS', []):
module, p_name = self._get_imported_stuff_by_path(processor_path)
if hasattr(module, p_name):
Expand All @@ -71,9 +85,46 @@ def _register_context_processors(self):
raise NoContextProcessorException('No {cp_name} context processor found'.format(cp_name=p_name))

def _register_blueprints(self):
if self.app.config.get('VERBOSE',False):
print 'registering blueprints'
self._bp = {}
for blueprint_path in self.app.config.get('BLUEPRINTS', []):
module, b_name = self._get_imported_stuff_by_path(blueprint_path)
if hasattr(module, b_name):
if hasattr(module, b_name):
self.app.register_blueprint(getattr(module, b_name))
self._bp[b_name] = getattr(module,b_name)
if self.app.config.get('VERBOSE',False):
print 'adding {} to bp'.format(b_name)
else:
raise NoBlueprintException('No {bp_name} blueprint found'.format(bp_name=b_name))

def _register_routes(self):
if self.app.config.get('VERBOSE',False):
print 'starting routing'
for url_module in self.app.config.get('URL_MODULES',[]):
if self.app.config.get('VERBOSE',False):
print url_module
module,r_name = self._get_imported_stuff_by_path(url_module)
if self.app.config.get('VERBOSE',False):
print r_name
print module
if hasattr(module,r_name):
if self.app.config.get('VERBOSE',False):
print 'setting {}'.format(r_name)
self._setup_routes(getattr(module,r_name))
else:
raise NoRouteModuleException('No {r_name} url module found'.format(r_name=r_name))

def _setup_routes(self,routes):
for route in routes:
blueprint,rules = route[0],route[1:]
for pattern, view in rules:
#print 'setting {} {} {}'.format(pattern,view,blueprint[0])
if type(blueprint) == type(tuple()):
blueprint = blueprint[0]
blueprint.add_url_rule(pattern,view_func=view)
if not blueprint in self.app.blueprints:
if self.app.config.get('VERBOSE',False):
print 'registering {}'.format(str(blueprint))
self.app.register_blueprint(blueprint)

8 changes: 8 additions & 0 deletions info/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from . import info
from .views import HelpPageView

routes = [
((info),
('',HelpPageView.as_view('help')),
)
]
1 change: 0 additions & 1 deletion info/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ class HelpPageView(MethodView):
def get(self):
return render_template('info/info_page.html')

info.add_url_rule('', view_func=HelpPageView.as_view('help'))
5 changes: 5 additions & 0 deletions local_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

class LocalConfig:
# put your sensitive local settings here
SECRET_KEY = 'jil'

Loading