3
0
Fork 0

feat: add People view; improve CRUD master for SQLAlchemy models

This commit is contained in:
Lance Edgar 2024-08-11 18:21:02 -05:00
parent fc01fa283a
commit 33589f1cd8
10 changed files with 275 additions and 43 deletions

View file

@ -815,8 +815,9 @@ class Form:
if self.readonly_fields:
schema = self.get_schema()
for field in self.readonly_fields:
del schema[field]
dform.children.remove(dform[field])
if field in schema:
del schema[field]
dform.children.remove(dform[field])
# let deform do real validation
controls = get_form_data(self.request).items()

View file

@ -97,11 +97,41 @@ class MenuHandler(GenericHandler):
is expected for most apps to override it.
The return value should be a list of dicts as described above.
The default logic returns a list of menus obtained from
calling these methods:
* :meth:`make_people_menu()`
* :meth:`make_admin_menu()`
"""
return [
self.make_people_menu(request),
self.make_admin_menu(request),
]
def make_people_menu(self, request, **kwargs):
"""
Generate a typical People menu.
This method provides a semi-sane menu set by default, but it
is expected for most apps to override it.
The return value for this method should be a *single* dict,
which will ultimately be one element of the final list of
dicts as described in :class:`MenuHandler`.
"""
return {
'title': "People",
'type': 'menu',
'items': [
{
'title': "All People",
'route': 'people',
'perm': 'people.list',
},
],
}
def make_admin_menu(self, request, **kwargs):
"""
Generate a typical Admin menu.
@ -111,7 +141,7 @@ class MenuHandler(GenericHandler):
The return value for this method should be a *single* dict,
which will ultimately be one element of the final list of
dicts as described above.
dicts as described in :class:`MenuHandler`.
"""
return {
'title': "Admin",

View file

@ -31,6 +31,8 @@ That will in turn include the following modules:
* :mod:`wuttaweb.views.auth`
* :mod:`wuttaweb.views.common`
* :mod:`wuttaweb.views.settings`
* :mod:`wuttaweb.views.people`
"""
@ -40,6 +42,7 @@ def defaults(config, **kwargs):
config.include(mod('wuttaweb.views.auth'))
config.include(mod('wuttaweb.views.common'))
config.include(mod('wuttaweb.views.settings'))
config.include(mod('wuttaweb.views.people'))
def includeme(config):

View file

@ -30,7 +30,7 @@ from sqlalchemy import orm
from pyramid.renderers import render_to_response
from wuttaweb.views import View
from wuttaweb.util import get_form_data
from wuttaweb.util import get_form_data, get_model_fields
from wuttaweb.db import Session
@ -292,6 +292,7 @@ class MasterView(View):
if form.validate():
obj = self.create_save_form(form)
Session.flush()
return self.redirect(self.get_action_url('view', obj))
context = {
@ -910,7 +911,8 @@ class MasterView(View):
kwargs['columns'] = self.get_grid_columns()
if 'data' not in kwargs:
kwargs['data'] = self.get_grid_data(session=session)
kwargs['data'] = self.get_grid_data(columns=kwargs['columns'],
session=session)
if 'actions' not in kwargs:
actions = []
@ -961,7 +963,7 @@ class MasterView(View):
if hasattr(self, 'grid_columns'):
return self.grid_columns
def get_grid_data(self, session=None):
def get_grid_data(self, columns=None, session=None):
"""
Returns the grid data for the :meth:`index()` view.
@ -974,8 +976,27 @@ class MasterView(View):
empty list. Subclass should override as needed.
"""
query = self.get_query(session=session)
if query is not None:
return query.all()
if query:
data = query.all()
# determine which columns are relevant for data set
if not columns:
columns = self.get_grid_columns()
if not columns:
model_class = self.get_model_class()
if model_class:
columns = get_model_fields(self.config, model_class)
if not columns:
raise ValueError("cannot determine columns for the grid")
columns = set(columns)
columns.update(self.get_model_key())
# prune data fields for which no column is defined
for i, record in enumerate(data):
data[i]= dict([(key, record[key])
for key in columns])
return data
return []
@ -1131,7 +1152,6 @@ class MasterView(View):
kwargs['model_instance'] = model_instance
# if 'fields' not in kwargs:
if not kwargs.get('fields'):
fields = self.get_form_fields()
if fields:
@ -1181,8 +1201,13 @@ class MasterView(View):
already be "complete" and ready to use as-is, but this method
can further modify it based on request details etc.
"""
model_keys = self.get_model_key()
if 'uuid' in form:
form.fields.remove('uuid')
if self.editing:
for key in self.get_model_key():
for key in model_keys:
form.set_readonly(key)
def objectify(self, form):

View file

@ -0,0 +1,95 @@
# -*- coding: utf-8; -*-
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024 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/>.
#
################################################################################
"""
Views for people
"""
from wuttjamaican.db.model import Person
from wuttaweb.views import MasterView
class PersonView(MasterView):
"""
Master view for people.
Notable URLs provided by this class:
* ``/people/``
* ``/people/new``
* ``/people/XXX``
* ``/people/XXX/edit``
* ``/people/XXX/delete``
"""
model_class = Person
model_title_plural = "People"
route_prefix = 'people'
grid_columns = [
'full_name',
'first_name',
'middle_name',
'last_name',
]
# TODO: master should handle this, possibly via configure_form()
def get_query(self, session=None):
""" """
model = self.app.model
query = super().get_query(session=session)
return query.order_by(model.Person.full_name)
def configure_grid(self, g):
""" """
super().configure_grid(g)
# full_name
g.set_link('full_name')
# TODO: master should handle this?
def configure_form(self, f):
""" """
super().configure_form(f)
# first_name
f.set_required('first_name', False)
# middle_name
f.set_required('middle_name', False)
# last_name
f.set_required('last_name', False)
# users
if 'users' in f:
f.fields.remove('users')
def defaults(config, **kwargs):
base = globals()
PersonView = kwargs.get('PersonView', base['PersonView'])
PersonView.defaults(config)
def includeme(config):
defaults(config)

View file

@ -26,12 +26,9 @@ Views for app settings
from collections import OrderedDict
import colander
from wuttjamaican.db.model import Setting
from wuttaweb.views import MasterView
from wuttaweb.util import get_libver, get_liburl
from wuttaweb.db import Session
class AppInfoView(MasterView):