diff --git a/adminplus/__init__.py b/adminplus/__init__.py index eb7506a..b01137a 100644 --- a/adminplus/__init__.py +++ b/adminplus/__init__.py @@ -10,3 +10,4 @@ VERSION = (0, 2, 'dev') __version__ = '.'.join(map(str, VERSION)) +__all__ = ['AdminSitePlus', 'site'] diff --git a/adminplus/models.py b/adminplus/models.py new file mode 100644 index 0000000..ce21d3e --- /dev/null +++ b/adminplus/models.py @@ -0,0 +1 @@ +# This module intentionally left blank. Only here for testing. diff --git a/adminplus/sites.py b/adminplus/sites.py index 5200aaf..8907c08 100644 --- a/adminplus/sites.py +++ b/adminplus/sites.py @@ -6,26 +6,38 @@ class AdminPlusMixin(object): """Mixin for AdminSite to allow registering custom admin views.""" index_template = 'adminplus/index.html' # That was easy. - custom_views = [] - def register_view(self, path, view, name=None, urlname=None, visible=True): - """Add a custom admin view. + def __init__(self, *args, **kwargs): + self.custom_views = [] + return super(AdminPlusMixin, self).__init__(*args, **kwargs) + + def register_view(self, path, name=None, urlname=None, visible=True, + view=None): + """Add a custom admin view. Can be used as a function or a decorator. * `path` is the path in the admin where the view will live, e.g. http://example.com/admin/somepath - * `view` is any view function you can imagine. * `name` is an optional pretty name for the list of custom views. If empty, we'll guess based on view.__name__. * `urlname` is an optional parameter to be able to call the view with a redirect() or reverse() * `visible` is a boolean to set if the custom view should be visible in the admin dashboard or not. + * `view` is any view function you can imagine. """ - self.custom_views.append((path, view, name, urlname, visible)) + if view is not None: + self.custom_views.append((path, view, name, urlname, visible)) + return + + def decorator(fn): + self.custom_views.append((path, fn, name, urlname, visible)) + return fn + return decorator + def get_urls(self): """Add our custom views to the admin urlconf.""" - urls = super(AdminSitePlus, self).get_urls() + urls = super(AdminPlusMixin, self).get_urls() from django.conf.urls.defaults import patterns, url for path, view, name, urlname, visible in self.custom_views: urls += patterns( @@ -51,7 +63,7 @@ def index(self, request, extra_context=None): extra_context.update({ 'custom_list': custom_list }) - return super(AdminSitePlus, self).index(request, extra_context) + return super(AdminPlusMixin, self).index(request, extra_context) class AdminSitePlus(AdminPlusMixin, AdminSite): diff --git a/adminplus/tests.py b/adminplus/tests.py new file mode 100644 index 0000000..f77840e --- /dev/null +++ b/adminplus/tests.py @@ -0,0 +1,69 @@ +from django.test import TestCase + +from adminplus.sites import AdminSitePlus + + +class AdminPlusTests(TestCase): + def test_decorator(self): + """register_view works as a decorator.""" + site = AdminSitePlus() + + @site.register_view(r'foo/bar') + def foo_bar(request): + return 'foo-bar' + + urls = site.get_urls() + assert any(u.resolve('foo/bar') for u in urls) + + def test_function(self): + """register_view works as a function.""" + site = AdminSitePlus() + + def foo(request): + return 'foo' + site.register_view('foo', view=foo) + + urls = site.get_urls() + assert any(u.resolve('foo') for u in urls) + + def test_path(self): + """Setting the path works correctly.""" + site = AdminSitePlus() + + def foo(request): + return 'foo' + site.register_view('foo', view=foo) + site.register_view('bar/baz', view=foo) + site.register_view('baz-qux', view=foo) + + urls = site.get_urls() + + matches = lambda u: lambda p: p.resolve(u) + foo_urls = filter(matches('foo'), urls) + self.assertEqual(1, len(foo_urls)) + bar_urls = filter(matches('bar/baz'), urls) + self.assertEqual(1, len(bar_urls)) + qux_urls = filter(matches('baz-qux'), urls) + self.assertEqual(1, len(qux_urls)) + + def test_urlname(self): + """Set URL pattern names correctly.""" + site = AdminSitePlus() + + @site.register_view('foo', urlname='foo') + def foo(request): + return 'foo' + + @site.register_view('bar') + def bar(request): + return 'bar' + + urls = site.get_urls() + matches = lambda u: lambda p: p.resolve(u) + foo_urls = filter(matches('foo'), urls) + self.assertEqual(1, len(foo_urls)) + self.assertEqual('foo', foo_urls[0].name) + + bar_urls = filter(matches('bar'), urls) + self.assertEqual(1, len(bar_urls)) + assert bar_urls[0].name is None diff --git a/test_settings.py b/test_settings.py index 1cbb3bd..174c10f 100644 --- a/test_settings.py +++ b/test_settings.py @@ -6,4 +6,12 @@ 'django.contrib.admin', 'adminplus', ) + SECRET_KEY = 'adminplus' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'test.db', + }, +}