Skip to content

Commit

Permalink
Merge pull request #20 from lamenezes/master
Browse files Browse the repository at this point in the history
add ModelAdmin.list_display
  • Loading branch information
lamenezes committed Jan 30, 2016
2 parents f415e4b + b6f7a4a commit 2cefaed
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 29 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ cov:
py.test --cov=bottle_admin tests/
covgui: cov
duvet
clean:
find bottle_admin/ tests/ -name *.pyc | xargs rm
2 changes: 1 addition & 1 deletion bottle_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from .sites import site

__all__ = ['site', 'AdminSite']
__all__ = ['site']


ADMIN_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)))
Expand Down
10 changes: 10 additions & 0 deletions bottle_admin/auth/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# coding: utf-8
from bottle_admin.options import ModelAdmin


class RoleAdmin(ModelAdmin):
list_display = ('role', 'level')


class UserAdmin(ModelAdmin):
list_display = ('username', 'role', 'email_addr', 'creation_date', 'last_login')
7 changes: 4 additions & 3 deletions bottle_admin/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def edit_model_get_controller(model_name, model_id):
obj = session.query(model.model_cls).get(model_id)
if not obj:
return u'{0} {1} not found'.format(model.name, model_id)
obj.as_list = get_object_as_list(obj)
obj.as_list = get_object_as_list(model, obj)
return {
'model': model,
'obj': obj
Expand Down Expand Up @@ -96,9 +96,10 @@ def list_model_controller(model_name):

model = site.get_model(model_name)
session = sessionmaker(bind=site.engine)()
objects = list(session.query(model.model_cls).all())
fields = model.get_select_fields()
objects = list(session.query(model.model_cls.id, *fields).all())

return {
'model': model,
'results': get_objects_as_list(objects),
'results': get_objects_as_list(model, objects),
}
22 changes: 11 additions & 11 deletions bottle_admin/helpers.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# coding: utf-8


def get_object_as_list(obj):
row_list = []
for col in obj.__table__.columns:
row_list.append((col.name, getattr(obj, col.name)))
return row_list
def get_object_as_list(model, obj):
"""Get the SQLAlchemy query result as a list of tuples"""

list_display = model.get_list_display()
result = [('id', obj.id)]
result += [(col, getattr(obj, col)) for col in list_display]
print(result)
return result

def get_objects_as_list(objs):
results = []
for obj in objs:
obj = get_object_as_list(obj)
results.append(obj)
return results

def get_objects_as_list(model, objs):
"""Get a list of SQLAlchemy queries as a list of list of tuples"""
return [get_object_as_list(model, obj) for obj in objs]
20 changes: 19 additions & 1 deletion bottle_admin/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ class ModelAdmin(object):
Extends the model to have admin functionalities
"""

list_display = tuple()

def __repr__(self):
return "<ModelAdmin('{0}')>".format(self.name)

def __init__(self, model):
def __init__(self, model, site):
from .sites import site
self.model_cls = model # the model class
self.site = site
self.name = self.model_cls.__name__.lower()
self.add_url = '{0}/{1}/add'.format(site.url_prefix, self.name)
self.list_url = '{0}/{1}'.format(site.url_prefix, self.name)
Expand All @@ -24,3 +27,18 @@ def columns(self):
mapper = inspect(self.model_cls)
attrs = [prop.columns[0] for prop in mapper.attrs]
return (prop.name for prop in attrs if prop.name != 'id')

def get_list_display(self):
return self.list_display

def get_select_fields(self):
list_display = self.get_list_display()
fields = []
for field in list_display:
attr = getattr(self.model_cls, field)
try:
attr = attr()
except:
pass
fields.append(attr)
return fields
19 changes: 10 additions & 9 deletions bottle_admin/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ def setup(self, engine, app):
auth.setup(self.engine)

def setup_models(self):
self.register(auth.User)
self.register(auth.Role)
from .auth.admin import RoleAdmin, UserAdmin
self.register(auth.Role, RoleAdmin)
self.register(auth.User, UserAdmin)

def setup_routing(self, app):
from .auth.controllers import (login_get_controller, login_post_controller,
Expand Down Expand Up @@ -101,16 +102,16 @@ def setup_routing(self, app):

app.mount(self.url_prefix, self.app)

def register(self, model, model_admin_cls=None):
if self.is_registered(model):
def register(self, model, admin_class=None):
if not admin_class:
admin_class = ModelAdmin
admin_obj = admin_class(model, self)

if self.is_registered(admin_obj):
message = u'Model {0} has already beeen registered'.format(model)
raise AlreadyRegistered(message)

if model_admin_cls:
model_admin = model_admin_cls(model)
else:
model_admin = ModelAdmin(model)
self._registry.append(model_admin)
self._registry.append(admin_obj)

def is_registered(self, model):
if type(model) is ModelAdmin:
Expand Down
2 changes: 1 addition & 1 deletion bottle_admin/views/admin/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ <h3 style="margin-top: 0px">{{ model.name|capitalize }}
<thead>
<tr>
<th>Actions</th>
{% for column in model.columns %}
{% for column in model.list_display %}
<th>{{ column }}</th>
{% endfor %}
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from bottle_admin import site
from bottle_admin.auth import get_aaa
from bottle_admin.auth.models import Role, User
from bottle_admin.options import ModelAdmin

ADMIN_TEMPLATE_PATH = os.path.join(os.path.dirname(bottle_admin.__path__[0]),
'bottle_admin',
Expand Down Expand Up @@ -44,8 +45,13 @@ def __repr__(self):

app = Bottle()


class ProductAdmin(ModelAdmin):
list_display = ('name', 'description', 'price')


site.setup(engine, app)
site.register(Product)
site.register(Product, ProductAdmin)

session_opts = {
'session.type': 'file',
Expand Down
File renamed without changes.
5 changes: 3 additions & 2 deletions tests/sites/test_options.py → tests/test_options.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# coding: utf-8
from bottle_admin import site
from bottle_admin.options import ModelAdmin
from bottle_admin.sites import AdminSite
# from sqlalchemy.orm import sessionmaker
Expand All @@ -21,11 +22,11 @@ def assert_model_meta(cls, model, columns):
assert model.delete_url == delete_url

def test_object(self):
user_model = ModelAdmin(User)
user_model = ModelAdmin(User, site)
columns = set(('username', 'fullname', 'hash', 'creation_date',
'role', 'email_addr', 'desc', 'last_login'))
TestAdminOptions.assert_model_meta(user_model, columns)

product_model = ModelAdmin(Product)
product_model = ModelAdmin(Product, site)
columns = set(('name', 'description', 'price'))
TestAdminOptions.assert_model_meta(product_model, columns)
7 changes: 7 additions & 0 deletions tests/sites/test_site.py → tests/test_site.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# coding: utf-8
import pytest
from bottle_admin.auth.models import User
from bottle_admin.options import ModelAdmin
from bottle_admin.sites import AdminSite, AlreadyRegistered, NotRegistered

from bottle_application import Product
Expand All @@ -25,6 +26,12 @@ def test_register(self, site):
site.register(User)
site.register(Product)

def test_is_registered(self, site):
assert site.is_registered(ModelAdmin(Product, site))
site.register(Product)
product = site._registry[0]
assert site.is_registered(product)

def test_get_model(self, site):
with pytest.raises(NotRegistered):
site.get_model('user')
Expand Down
File renamed without changes.

0 comments on commit 2cefaed

Please sign in to comment.