feat: add basic Table views
very minimal so far, just laying foundations
This commit is contained in:
parent
d6a4c5e657
commit
6791abe96f
6 changed files with 212 additions and 0 deletions
6
docs/api/wuttaweb.views.tables.rst
Normal file
6
docs/api/wuttaweb.views.tables.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
``wuttaweb.views.tables``
|
||||
=========================
|
||||
|
||||
.. automodule:: wuttaweb.views.tables
|
||||
:members:
|
||||
|
|
@ -70,6 +70,7 @@ the narrative docs are pretty scant. That will eventually change.
|
|||
api/wuttaweb.views.reports
|
||||
api/wuttaweb.views.roles
|
||||
api/wuttaweb.views.settings
|
||||
api/wuttaweb.views.tables
|
||||
api/wuttaweb.views.upgrades
|
||||
api/wuttaweb.views.users
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,18 @@
|
|||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="buttons">
|
||||
|
||||
% if request.has_perm("tables.list"):
|
||||
<wutta-button type="is-primary"
|
||||
tag="a" href="${url('tables')}"
|
||||
icon-left="table"
|
||||
label="Database Tables"
|
||||
once />
|
||||
% endif
|
||||
|
||||
</div>
|
||||
|
||||
<nav class="panel">
|
||||
<p class="panel-heading">Configuration Files</p>
|
||||
<div class="panel-block">
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ That will in turn include the following modules:
|
|||
* :mod:`wuttaweb.views.roles`
|
||||
* :mod:`wuttaweb.views.users`
|
||||
* :mod:`wuttaweb.views.upgrades`
|
||||
* :mod:`wuttaweb.views.tables`
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -55,6 +56,7 @@ def defaults(config, **kwargs): # pylint: disable=missing-function-docstring
|
|||
config.include(mod("wuttaweb.views.roles"))
|
||||
config.include(mod("wuttaweb.views.users"))
|
||||
config.include(mod("wuttaweb.views.upgrades"))
|
||||
config.include(mod("wuttaweb.views.tables"))
|
||||
|
||||
|
||||
def includeme(config): # pylint: disable=missing-function-docstring
|
||||
|
|
|
|||
135
src/wuttaweb/views/tables.py
Normal file
135
src/wuttaweb/views/tables.py
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# wuttaweb -- Web App for Wutta Framework
|
||||
# Copyright © 2024-2025 Lance Edgar
|
||||
#
|
||||
# This file is part of Wutta Framework.
|
||||
#
|
||||
# Wutta Framework is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# Wutta Framework is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Table Views
|
||||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
from wuttaweb.views import MasterView
|
||||
|
||||
|
||||
class TableView(MasterView):
|
||||
"""
|
||||
Master view showing all tables in the :term:`app database`.
|
||||
|
||||
Default route prefix is ``tables``.
|
||||
|
||||
Notable URLs provided by this class:
|
||||
|
||||
* ``/tables/``
|
||||
"""
|
||||
|
||||
model_name = "table"
|
||||
model_title = "Database Table"
|
||||
model_key = "name"
|
||||
filterable = False
|
||||
sortable = True
|
||||
sort_on_backend = False
|
||||
paginated = True
|
||||
paginate_on_backend = False
|
||||
creatable = False
|
||||
editable = False
|
||||
deletable = False
|
||||
|
||||
labels = {
|
||||
"name": "Table Name",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
"name",
|
||||
"schema",
|
||||
# "row_count",
|
||||
]
|
||||
|
||||
sort_defaults = "name"
|
||||
|
||||
form_fields = [
|
||||
"name",
|
||||
"schema",
|
||||
# "row_count",
|
||||
]
|
||||
|
||||
def get_grid_data( # pylint: disable=empty-docstring
|
||||
self, columns=None, session=None
|
||||
):
|
||||
""" """
|
||||
model = self.app.model
|
||||
data = []
|
||||
|
||||
for table in model.Base.metadata.tables.values():
|
||||
data.append(
|
||||
{
|
||||
"name": table.name,
|
||||
"schema": table.schema or "",
|
||||
# "row_count": 42,
|
||||
}
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
def configure_grid(self, grid): # pylint: disable=empty-docstring
|
||||
""" """
|
||||
g = grid
|
||||
super().configure_grid(g)
|
||||
|
||||
# schema
|
||||
g.set_searchable("schema")
|
||||
|
||||
# name
|
||||
g.set_searchable("name")
|
||||
g.set_link("name")
|
||||
|
||||
def get_instance(self): # pylint: disable=empty-docstring
|
||||
""" """
|
||||
if "_cached_instance" not in self.__dict__:
|
||||
model = self.app.model
|
||||
|
||||
name = self.request.matchdict["name"]
|
||||
table = model.Base.metadata.tables[name]
|
||||
data = {
|
||||
"name": table.name,
|
||||
"schema": table.schema or "",
|
||||
# "row_count": 42,
|
||||
}
|
||||
|
||||
self.__dict__["_cached_instance"] = data
|
||||
|
||||
return self.__dict__["_cached_instance"]
|
||||
|
||||
def get_instance_title(self, instance): # pylint: disable=empty-docstring
|
||||
""" """
|
||||
return instance["name"]
|
||||
|
||||
|
||||
def defaults(config, **kwargs): # pylint: disable=missing-function-docstring
|
||||
base = globals()
|
||||
|
||||
TableView = kwargs.get( # pylint: disable=invalid-name,redefined-outer-name
|
||||
"TableView", base["TableView"]
|
||||
)
|
||||
TableView.defaults(config)
|
||||
|
||||
|
||||
def includeme(config): # pylint: disable=missing-function-docstring
|
||||
defaults(config)
|
||||
56
tests/views/test_tables.py
Normal file
56
tests/views/test_tables.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from wuttaweb.testing import WebTestCase
|
||||
from wuttaweb.views import tables as mod
|
||||
|
||||
|
||||
class TestUpgradeView(WebTestCase):
|
||||
|
||||
def make_view(self):
|
||||
return mod.TableView(self.request)
|
||||
|
||||
def test_includeme(self):
|
||||
self.pyramid_config.include("wuttaweb.views.tables")
|
||||
|
||||
def test_get_grid_data(self):
|
||||
view = self.make_view()
|
||||
data = view.get_grid_data()
|
||||
self.assertIsInstance(data, list)
|
||||
self.assertGreater(len(data), 0)
|
||||
table = data[0]
|
||||
self.assertIsInstance(table, dict)
|
||||
self.assertIn("name", table)
|
||||
self.assertIn("schema", table)
|
||||
|
||||
def test_configure_grid(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# sanity / coverage check
|
||||
grid = view.make_grid(columns=["name", "schema"])
|
||||
view.configure_grid(grid)
|
||||
|
||||
def test_get_instance(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
with patch.object(self.request, "matchdict", new={"name": "person"}):
|
||||
|
||||
table1 = view.get_instance()
|
||||
self.assertIsInstance(table1, dict)
|
||||
self.assertIn("name", table1)
|
||||
self.assertEqual(table1["name"], "person")
|
||||
self.assertIn("schema", table1)
|
||||
|
||||
table2 = view.get_instance()
|
||||
self.assertIs(table2, table1)
|
||||
self.assertEqual(table2["name"], "person")
|
||||
|
||||
def test_get_instance_title(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
table = {"name": "poser_foo"}
|
||||
self.assertEqual(view.get_instance_title(table), "poser_foo")
|
||||
Loading…
Add table
Add a link
Reference in a new issue