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:
tgext.admin.config.
AdminConfig
(models, translations=None)¶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