Commit 989ac1c8 authored by Serge S. Koval's avatar Serge S. Koval

Added ability to change admin base URL.

parent 37ae5a07
...@@ -16,18 +16,16 @@ app.config['SQLALCHEMY_ECHO'] = True ...@@ -16,18 +16,16 @@ app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app) db = SQLAlchemy(app)
# Create model # Create models
class User(db.Model): class User(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True) username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True) email = db.Column(db.String(120), unique=True)
# Required for administrative interface
def __unicode__(self): def __unicode__(self):
return self.username return self.username
def __repr__(self):
return '<User %r>' % self.username
class Post(db.Model): class Post(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
...@@ -41,32 +39,43 @@ class Post(db.Model): ...@@ -41,32 +39,43 @@ class Post(db.Model):
return self.title return self.title
# Flask routes # Flask views
@app.route('/') @app.route('/')
def index(): def index():
db.session.query(Post).join(User).order_by(User.username).all()
return '<a href="/admin/">Click me to get to Admin!</a>' return '<a href="/admin/">Click me to get to Admin!</a>'
# Customized Post model admin
class PostAdmin(sqlamodel.ModelView): class PostAdmin(sqlamodel.ModelView):
# Visible columns in the list view
list_columns = ('title', 'user') list_columns = ('title', 'user')
# List of columns that can be sorted. For 'user' column, use User.username as
# a column.
sortable_columns = ('title', ('user', User.username)) sortable_columns = ('title', ('user', User.username))
rename_columns = dict(title='Tiiitle')
# Rename 'title' columns to 'Post Title' in list view
rename_columns = dict(title='Post Title')
# Pass arguments to WTForms. In this case, change label for text field to
# be 'Big Text' and add required() validator.
form_args = dict( form_args = dict(
text=dict(label='Big Text', validators=[wtf.required()]) text=dict(label='Big Text', validators=[wtf.required()])
) )
def __init__(self, session): def __init__(self, session):
# Just call parent class with predefined model.
super(PostAdmin, self).__init__(Post, session) super(PostAdmin, self).__init__(Post, session)
if __name__ == '__main__': if __name__ == '__main__':
# Create admin # Create admin
admin = adminex.Admin('Simple Models') admin = adminex.Admin('Simple Models')
# Add views
admin.add_view(sqlamodel.ModelView(User, db.session)) admin.add_view(sqlamodel.ModelView(User, db.session))
admin.add_view(PostAdmin(db.session)) admin.add_view(PostAdmin(db.session))
# Associate with an app
admin.apply(app) admin.apply(app)
# Create DB # Create DB
......
...@@ -105,30 +105,24 @@ class BaseView(object): ...@@ -105,30 +105,24 @@ class BaseView(object):
self.url = url self.url = url
self.static_folder = static_folder self.static_folder = static_folder
# Initialized from create_blueprint
self.admin = None self.admin = None
self.blueprint = None
self._create_blueprint() def create_blueprint(self, admin):
def _set_admin(self, admin):
""" """
Associate this view with Admin class instance. Create Flask blueprint.
`admin`
Admin instance
""" """
# Store admin instance
self.admin = admin self.admin = admin
def _create_blueprint(self):
"""
Create Flask blueprint.
"""
# If endpoint name is not provided, get it from the class name # If endpoint name is not provided, get it from the class name
if self.endpoint is None: if self.endpoint is None:
self.endpoint = self.__class__.__name__.lower() self.endpoint = self.__class__.__name__.lower()
# If url is not provided, generate it from endpoint name # If url is not provided, generate it from endpoint name
if self.url is None: if self.url is None:
self.url = '/admin/%s' % self.endpoint self.url = '%s/%s' % (self.admin.url, self.endpoint)
# If name is not povided, use capitalized endpoint name # If name is not povided, use capitalized endpoint name
if self.name is None: if self.name is None:
...@@ -146,6 +140,8 @@ class BaseView(object): ...@@ -146,6 +140,8 @@ class BaseView(object):
getattr(self, name), getattr(self, name),
methods=methods) methods=methods)
return self.blueprint
def _prettify_name(self, name): def _prettify_name(self, name):
""" """
Prettify class name by splitting name by capital characters. So, 'MySuperClass' will look like 'My Super Class' Prettify class name by splitting name by capital characters. So, 'MySuperClass' will look like 'My Super Class'
...@@ -249,7 +245,7 @@ class Admin(object): ...@@ -249,7 +245,7 @@ class Admin(object):
""" """
Collection of the views. Also manages menu structure. Collection of the views. Also manages menu structure.
""" """
def __init__(self, name=None, index_view=None): def __init__(self, name=None, url=None, index_view=None):
""" """
Constructor. Constructor.
...@@ -265,6 +261,10 @@ class Admin(object): ...@@ -265,6 +261,10 @@ class Admin(object):
name = 'Admin' name = 'Admin'
self.name = name self.name = name
if url is None:
url = '/admin'
self.url = url
if index_view is None: if index_view is None:
index_view = AdminIndexView() index_view = AdminIndexView()
...@@ -278,7 +278,6 @@ class Admin(object): ...@@ -278,7 +278,6 @@ class Admin(object):
`view` `view`
View to add. View to add.
""" """
view._set_admin(self)
self._views.append(view) self._views.append(view)
def apply(self, app): def apply(self, app):
...@@ -291,7 +290,7 @@ class Admin(object): ...@@ -291,7 +290,7 @@ class Admin(object):
self.app = app self.app = app
for v in self._views: for v in self._views:
app.register_blueprint(v.blueprint) app.register_blueprint(v.create_blueprint(self))
self._refresh_menu() self._refresh_menu()
......
...@@ -8,8 +8,6 @@ from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleF ...@@ -8,8 +8,6 @@ from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleF
from flask import flash from flask import flash
from flaskext import wtf
from flask.ext.adminex.model import BaseModelView from flask.ext.adminex.model import BaseModelView
from flask.ext.adminex.form import AdminForm from flask.ext.adminex.form import AdminForm
......
...@@ -7,17 +7,17 @@ class BaseModelView(BaseView): ...@@ -7,17 +7,17 @@ class BaseModelView(BaseView):
""" """
Base model view. Base model view.
Does not make any assumptions on how models are stored or managed, but expects following: View does not make any assumptions on how models are stored or managed, but expects following:
1. Model is an object 1. Model is an object
2. Model contains properties 2. Model contains properties
3. Each model contains 'id' attribute which uniquely identifies it (TBD: Make it more flexible) 3. Each model contains attribute which uniquely identifies it (i.e. primary key for database model)
4. You can get list of sorted models with pagination applied from a data source 4. You can get list of sorted models with pagination applied from a data source
5. You can get one model by its 'id' from the data source 5. You can get one model by its identifier from the data source
Essentially, if you want to support new data store, all you have to do: Essentially, if you want to support new data store, all you have to do:
1. Derive from `BaseModelView` class 1. Derive from `BaseModelView` class
2. Implement various data-related methods (`get_list`, `get_one`, `create_model`, etc) 2. Implement various data-related methods (`get_list`, `get_one`, `create_model`, etc)
3. Implement automatic form generation from the model representation (`scaffold_form`, etc) 3. Implement automatic form generation from the model representation (`scaffold_form`)
""" """
# Permissions # Permissions
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment