Permalink
Browse files

Merge branch 'release/0.1.0'

  • Loading branch information...
2 parents 550178a + 3593322 commit 6484a68348008fda47211e927b928339b5e7d9c3 @klen committed Jul 11, 2012
View
@@ -0,0 +1,8 @@
+*.pyc
+.env
+.ropeproject
+.tests
+.vimrc
+.db
+.tags
+._
View
@@ -0,0 +1,4 @@
+2012-07-11 klen
+
+ * Version 0.1.0
+ * Initial release
View
@@ -0,0 +1,51 @@
+ENVBIN=$(CURDIR)/.env/bin
+PIP=$(ENVBIN)/pip
+PYTHON=$(ENVBIN)/python
+PYBABEL=$(ENVBIN)/pybabel
+BABELDIR=$(CURDIR)/base/translations
+CONFIG=base.settings.Develop
+
+all: .env
+
+.env: requirements.txt
+ virtualenv --no-site-packages .env
+ $(PIP) install -M -r requirements.txt
+
+
+.PHONY: shell
+shell: .env/ manage.py
+ $(PYTHON) manage.py shell -c $(CONFIG)
+
+
+.PHONY: run
+run: .env/ manage.py
+ $(PYTHON) manage.py runserver -c $(CONFIG)
+
+
+.PHONY: db
+db: .env/ manage.py
+ $(PYTHON) manage.py create_db -c $(CONFIG)
+
+.db: db
+
+.PHONY: migrate
+migrate: .env/ manage.py .db
+ $(PYTHON) manage.py migrate run -c $(CONFIG)
+
+.PHONY: test
+test: .env/ manage.py
+ nosetests
+
+.PHONY: clean
+clean:
+ find $(CURDIR) -name "*.pyc" -delete
+ find $(CURDIR) -name "*.orig" -delete
+
+.PHONY: babel
+babel: $(BABELDIR)/ru
+ $(PYBABEL) extract -F $(BABELDIR)/babel.ini -k _gettext -k _ngettext -k lazy_gettext -o $(BABELDIR)/babel.pot --project Flask-base $(CURDIR)
+ $(PYBABEL) update -i $(BABELDIR)/babel.pot -d $(BABELDIR)
+ $(PYBABEL) compile -d $(BABELDIR)
+
+$(BABELDIR)/ru:
+ $(PYBABEL) init -i $(BABELDIR)/babel.pot -d $(BABELDIR) -l ru
View
@@ -0,0 +1,29 @@
+Flask Template Project
+======================
+
+Quick start with Flask.
+
+* `Flask-Bootstrap <http://github.com/mbr/flask-bootstrap>`_ (markup);
+* `Flask-SQLAlchemy <http://github.com/mitsuhiko/flask-sqlalchemy>` (ORM);
+* `Flask-WTF <http://github.com/rduplain/flask-wtf>`_ (forms);
+* `Flask-Evolution <http://pypi.python.org/pypi/Flask-Evolution/0.5>`_ (migration);
+* `Flask-babel <http://github.com/mitsuhiko/flask-babel>`_ (i18n);
+* `Flask-admin <https://github.com/mrjoes/flask-admin/>`_ (administration);
+* `Flask-script <http://github.com/rduplain/flask-script>`_ (administration);
+* Included user authentication system;
+* Usefull makefile shortcuts (make run, make db and etc);
+
+
+Instalation:
+------------
+::
+ git clone https://github.com/klen/flask-template.git
+ cd flask-template
+ make migrate
+
+
+Usage:
+------
+
+Run development server: ::
+ make run
View
@@ -0,0 +1 @@
+__version__ = "0.1.0"
View
@@ -0,0 +1,22 @@
+from flask.ext.admin import AdminIndexView, Admin
+from flask.ext.admin.contrib.sqlamodel import ModelView
+from flask.ext.login import current_user
+
+
+class StaffAdminView(AdminIndexView):
+ " Staff admin home page. "
+ def is_accessible(self):
+ return current_user.permission('staff')
+
+
+class AuthModelView(ModelView):
+ def __init__(self, *args, **kwargs):
+ self.role = kwargs.pop('role', None) or 'admin'
+ super(AuthModelView, self).__init__(*args, **kwargs)
+
+ def is_accessible(self):
+ return current_user.permission(self.role)
+
+
+# Create admin
+admin = Admin(name='Admin', index_view=StaffAdminView())
View
@@ -0,0 +1,43 @@
+from flask import Flask, render_template, request
+from flask.ext.sqlalchemy import SQLAlchemy
+from flask.ext.bootstrap import Bootstrap
+
+import settings
+
+
+db = SQLAlchemy()
+
+
+def create_app(config=None, **skip):
+ app = Flask(__name__)
+ app.config.from_object(config or settings.Production)
+ app.config.from_envvar("APP_SETTINGS", silent=True)
+ db.init_app(app)
+
+ # Main urlconfig
+ from views import urls
+ app.register_blueprint(urls)
+
+ # Users support
+ from users.views import users
+ app.register_blueprint(users)
+
+ # Admin
+ from admin import admin
+ admin.init_app(app)
+
+ # Bootstrap
+ Bootstrap(app)
+
+ # Localization
+ from flask.ext.babel import Babel
+ babel = Babel(app)
+
+ @babel.localeselector
+ def get_locale():
+ return 'ru'
+ return request.accept_languages.best_match(['en', 'ru'])
+
+ app.errorhandler(404)(lambda e: (render_template('404.html'), 404))
+
+ return app
View
@@ -0,0 +1,102 @@
+from datetime import datetime
+
+from sqlalchemy import Column, Integer, DateTime
+from sqlalchemy.ext.declarative import declared_attr
+from sqlalchemy.orm import object_mapper
+from sqlalchemy.orm.session import object_session
+
+
+class UpdateMixin(object):
+ """Provides the 'update' convenience function to allow class
+ properties to be written via keyword arguments when the object is
+ already initialised.
+
+ .. code-block: python
+
+ class Person(Base, UpdateMixin):
+ name = Column(String(19))
+
+ >>> person = Person(name='foo')
+ >>> person.update(**{'name': 'bar'})
+
+ """
+
+ def update(self, **kw):
+ for k in kw:
+ if hasattr(self, k):
+ setattr(self, k, kw[k])
+
+
+class TimestampMixin(object):
+ """Adds automatically updated created_at and updated_at timestamp
+ columns to a table, that unsurprisingly are updated on record INSERT and
+ UPDATE. UTC time is used in both cases.
+ """
+
+ created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
+ updated_at = Column(DateTime, onupdate=datetime.utcnow)
+
+
+class BaseMixin(UpdateMixin, TimestampMixin):
+ """Provieds all benefits of
+ :class:`~pyramid_alchauth.models.UpdateMixin` and
+ :class:`~pyramid_alchauth.models.TimestampMixin` as well as
+ providing a deform compatible appstruct property and an easy way to
+ query VersionedMeta. It also defines an id column to save on boring
+ boilerplate.
+ """
+
+ id = Column(Integer, primary_key=True)
+
+ @declared_attr
+ def __tablename__(cls):
+ return cls.__name__.lower()
+
+ @property
+ def session(self):
+ return object_session(self)
+
+ @property
+ def _history_class(self):
+ """Returns the corresponding history class if the inheriting
+ class supports versioning (by checking for the existence of a
+ '__history_mapper__' attribute). Otherwise, returns None.
+ """
+ if hasattr(self, '__history_mapper__'):
+ return self.__history_mapper__.class_
+ else:
+ return None
+
+ @property
+ def history(self):
+ """Returns an SQLAlchemy query of the object's history (previous
+ versions). If the class does not support history/versioning,
+ returns None.
+ """
+ history = self.history_class
+ if history:
+ return self.session.query(history).filter(history.id == self.id)
+ else:
+ return None
+
+ def generate_appstruct(self):
+ """Returns a Deform compatible appstruct of the object and it's
+ properties. Does not recurse into SQLAlchemy relationships.
+ An example using the :class:`~drinks.models.User` class (that
+ inherits from BaseMixin):
+
+ .. code-block:: python
+
+ >>> user = User(username='mcuserpants', disabled=True)
+ >>> user.appstruct
+ {'disabled': True, 'username': 'mcuserpants'}
+
+ """
+ mapper = object_mapper(self)
+ return dict([(p.key, self.__getattribute__(p.key)) for
+ p in mapper.iterate_properties if
+ not self.__getattribute__(p.key) is None])
+
+ @property
+ def appstruct(self):
+ return self.generate_appstruct()
@@ -0,0 +1,23 @@
+from flask.ext.evolution import BaseMigration
+
+
+class Migration(BaseMigration):
+
+ def up(self):
+ from base.app import db
+ from base.users.models import Role, User
+
+ admin = Role(name='admin')
+ staff = Role(name='staff')
+
+ user = User(username='admin',
+ email='admin@admin.com',
+ pw_hash='admin')
+
+ user.roles.append(admin)
+ user.roles.append(staff)
+ db.session.add(user)
+ db.session.commit()
+
+ def down(self):
+ raise TypeError("down is not defined")
View
@@ -0,0 +1,26 @@
+from flask.ext.script import Command, prompt_bool
+
+
+class CreateDB(Command):
+ " Create DB structure. "
+
+ def run(self):
+ from base.app import db
+ db.create_all()
+ print "Database created successfuly"
+
+
+class DropDB(Command):
+ " Drops all database tables. "
+ def run(self):
+ from base.app import db
+ if prompt_bool("Are you sure? You will lose all your data!"):
+ db.drop_all()
+ print "Database clearing"
+
+
+class ResetDB(Command):
+ " Reset DB. "
+ def run(self):
+ DropDB().run()
+ CreateDB().run()
View
@@ -0,0 +1,30 @@
+from os import path as op
+
+
+__basedir__ = op.abspath(op.dirname(op.dirname(__file__)))
+
+
+class Config(object):
+ DEBUG = False
+ TESTING = False
+ SQLALCHEMY_DATABASE_URI = 'sqlite:///' + op.join(__basedir__, '.db')
+ CSRF_ENABLED = True
+ CSRF_SESSION_KEY = "somethingimpossibletoguess"
+
+
+class Production(Config):
+ ADMINS = frozenset(['youremail@yourdomain.com'])
+ SECRET_KEY = 'SecretKeyForSessionSigning'
+ DATABASE_CONNECT_OPTIONS = {}
+ BABEL_DEFAULT_LOCALE = 'en'
+
+
+class Testing(Production):
+ TESTING = True
+ SQLALCHEMY_DATABASE_URI = 'sqlite://:memory:'
+ SQLALCHEMY_ECHO = True
+
+
+class Develop(Production):
+ DEBUG = True
+ SQLALCHEMY_ECHO = True
Oops, something went wrong.

0 comments on commit 6484a68

Please sign in to comment.