TurboGears provides the tgext.admin extension which is powered by tgext.crud and sprox. This can be used to automatically create simple administration pages and is the toolkit powering the /admin page in newly quickstarted applications.
By default the admin will provide autogenerated access to all the models imported in your project models/__init__.py.
While the default configuration for the admin usually just works it doesn’t provide the best experience for users and might require some customizations.
To do so the TurboGears Admin permits to provide custom configurations throught the AdminController config_type paramter.
The default turbogears admin is created as:
admin = AdminController(model, DBSession, config_type=TGAdminConfig)
which creates an admin for all the models with the default TurboGears admin configuration.
Restricting access to some models is possible by specifying them explicitly instead of passing model as the first argument to the AdminController:
from myproject.model import User, Group
admin = AdminController([User, Group], DBSession, config_type=TGAdminConfig)
First step to perform if you want to switch to a customized administration configuration is to declare your own config. This can easily be done by subclassing TGAdminConfig:
class CustomAdminConfig(TGAdminConfig):
pass
if you replace config_type=TGAdminConfig with your new CustomAdminConfig:
admin = AdminController(model, DBSession, config_type=CustomAdminConfig)
You will notice that everything works as before, as we didn’t change the configuration in any way. The custom configuration will contains properties for the admin itself and for each CRUD inside the admin.
Apart from configuration for each crud, there are some general admin configuration options:
Class attributes: | |
---|---|
|
The admin page can be configured using the TGAdminConfig class, supposing we have a game with running Match and a list of Settings we can declared MatchAdminController and SettingAdminController which inherit from EasyCrudRestController and tell TurboGears Admin to use them for the administration of matches and settings:
class CustomAdminConfig(TGAdminConfig):
class match(CrudRestControllerConfig):
defaultCrudRestController = MatchAdminController
class setting(CrudRestControllerConfig):
defaultCrudRestController = SettingAdminController
class RootController(BaseController):
admin = AdminController([model.Match, model.Setting], DBSession,
config_type=CustomAdminConfig)
This will create an administration controller which uses our custom CrudRestControllers to manage Match and Settings instances.
Each class attribute of our CustomAdminConfig that has the lower case name of a Model will be used to configure the admin CRUD for that model.
This can be done by subclassing CrudRestControllerConfig with a defaultCrudRestController class attribute that points to the CrudRestController class to use for the related model.
The explicit way to define models configuration is by declaring CrudRestControllers and configurations separately, but in case the custom controllers are required only for the admin it might be shortest to just define them together:
class MyModelAdminCrudConfig(CrudRestControllerConfig):
class defaultCrudRestController(EasyCrudRestController):
__table_options__ = {
# options here...
}
class CustomAdminConfig(TGAdminConfig):
photo = MyModelAdminCrudConfig
For a complete list of options available inside defaultCrudRestController refer to TurboGears Automatic CRUD Generation.
Now suppose we have a photo model that looks like:
class Photo(DeclarativeBase):
__tablename__ = 'photos'
uid = Column(Integer, primary_key=True)
title = Column(Unicode(255), nullable=False)
image = Column(LargeBinary, nullable=False)
mimetype = Column(Unicode(64), nullable=False, default='image/jpeg')
user_id = Column(Integer, ForeignKey('tg_user.user_id'), index=True)
user = relationship('User', uselist=False,
backref=backref('photos',
cascade='all, delete-orphan'))
we might want to customize our admin to use the GroupedBootstrapAdminLayout layout, put the photos inside the Media group and improve the table view for the crud by removing the user_id and mimetype columns and declare the image column as xml so that we can show the image inside:
import base64
from tgext.admin import CrudRestControllerConfig
from tgext.admin.tgadminconfig import BootstrapTGAdminConfig as TGAdminConfig
from tgext.admin.layouts import GroupedBootstrapAdminLayout
from tgext.admin.controller import AdminController as TGAdminController
from tgext.crud import EasyCrudRestController
class PhotoAdminCrudConfig(CrudRestControllerConfig):
icon_class = 'glyphicon-picture'
admin_group = 'Media'
class defaultCrudRestController(EasyCrudRestController):
__table_options__ = {
'__omit_fields__': ['user_id', 'mimetype'],
'__xml_fields__': ['image'],
'image': lambda filler, row: '<img src="data:%s;base64,%s" width="256"/>' % (
row.mimetype,
base64.b64encode(row.image).decode('ascii')
)
}
class CustomAdminConfig(TGAdminConfig):
layout = GroupedBootstrapAdminLayout
photo = PhotoAdminCrudConfig
Now our admin works as expected and uses the PhotoAdminCrudConfig to manage photos. There is still an open issue, when uploading photos we have to manually provide the photo user and mimetype.
To solve this issue we will customize the form hiding the two values from the form and forcing them when data is submitted:
import base64, imghdr
from tg import expose, request
from tgext.admin import CrudRestControllerConfig
from tgext.admin.tgadminconfig import BootstrapTGAdminConfig as TGAdminConfig
from tgext.admin.layouts import GroupedBootstrapAdminLayout
from tgext.admin.controller import AdminController as TGAdminController
from tgext.crud import EasyCrudRestController
class PhotoAdminCrudConfig(CrudRestControllerConfig):
icon_class = 'glyphicon-picture'
admin_group = 'Media'
class defaultCrudRestController(EasyCrudRestController):
__table_options__ = {
'__omit_fields__': ['user_id', 'mimetype'],
'__xml_fields__': ['image'],
'image': lambda filler, row: '<img src="data:%s;base64,%s" width="256"/>' % (
row.mimetype,
base64.b64encode(row.image).decode('ascii')
)
}
__form_options__ = {
'__hide_fields__': ['user', 'mimetype']
}
@expose(inherit=True)
def post(self, *args, **kw):
kw['user'] = request.identity['user'].user_id
kw['mimetype'] = 'image/%s' % imghdr.what(kw['image'].file)
return EasyCrudRestController.post(self, *args, **kw)
@expose(inherit=True)
def put(self, *args, **kw):
image = kw.get('image')
if image is not None and image.filename:
kw['mimetype'] = 'image/%s' % imghdr.what(kw['image'].file)
return EasyCrudRestController.put(self, *args, **kw)
class CustomAdminConfig(TGAdminConfig):
layout = GroupedBootstrapAdminLayout
photo = PhotoAdminCrudConfig