feat: add People view; improve CRUD master for SQLAlchemy models
This commit is contained in:
parent
fc01fa283a
commit
33589f1cd8
|
@ -26,4 +26,5 @@
|
||||||
views.common
|
views.common
|
||||||
views.essential
|
views.essential
|
||||||
views.master
|
views.master
|
||||||
|
views.people
|
||||||
views.settings
|
views.settings
|
||||||
|
|
6
docs/api/wuttaweb/views.people.rst
Normal file
6
docs/api/wuttaweb/views.people.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
``wuttaweb.views.people``
|
||||||
|
===========================
|
||||||
|
|
||||||
|
.. automodule:: wuttaweb.views.people
|
||||||
|
:members:
|
|
@ -815,6 +815,7 @@ class Form:
|
||||||
if self.readonly_fields:
|
if self.readonly_fields:
|
||||||
schema = self.get_schema()
|
schema = self.get_schema()
|
||||||
for field in self.readonly_fields:
|
for field in self.readonly_fields:
|
||||||
|
if field in schema:
|
||||||
del schema[field]
|
del schema[field]
|
||||||
dform.children.remove(dform[field])
|
dform.children.remove(dform[field])
|
||||||
|
|
||||||
|
|
|
@ -97,11 +97,41 @@ class MenuHandler(GenericHandler):
|
||||||
is expected for most apps to override it.
|
is expected for most apps to override it.
|
||||||
|
|
||||||
The return value should be a list of dicts as described above.
|
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 [
|
return [
|
||||||
|
self.make_people_menu(request),
|
||||||
self.make_admin_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):
|
def make_admin_menu(self, request, **kwargs):
|
||||||
"""
|
"""
|
||||||
Generate a typical Admin menu.
|
Generate a typical Admin menu.
|
||||||
|
@ -111,7 +141,7 @@ class MenuHandler(GenericHandler):
|
||||||
|
|
||||||
The return value for this method should be a *single* dict,
|
The return value for this method should be a *single* dict,
|
||||||
which will ultimately be one element of the final list of
|
which will ultimately be one element of the final list of
|
||||||
dicts as described above.
|
dicts as described in :class:`MenuHandler`.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'title': "Admin",
|
'title': "Admin",
|
||||||
|
|
|
@ -31,6 +31,8 @@ That will in turn include the following modules:
|
||||||
|
|
||||||
* :mod:`wuttaweb.views.auth`
|
* :mod:`wuttaweb.views.auth`
|
||||||
* :mod:`wuttaweb.views.common`
|
* :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.auth'))
|
||||||
config.include(mod('wuttaweb.views.common'))
|
config.include(mod('wuttaweb.views.common'))
|
||||||
config.include(mod('wuttaweb.views.settings'))
|
config.include(mod('wuttaweb.views.settings'))
|
||||||
|
config.include(mod('wuttaweb.views.people'))
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
|
|
|
@ -30,7 +30,7 @@ from sqlalchemy import orm
|
||||||
from pyramid.renderers import render_to_response
|
from pyramid.renderers import render_to_response
|
||||||
|
|
||||||
from wuttaweb.views import View
|
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
|
from wuttaweb.db import Session
|
||||||
|
|
||||||
|
|
||||||
|
@ -292,6 +292,7 @@ class MasterView(View):
|
||||||
|
|
||||||
if form.validate():
|
if form.validate():
|
||||||
obj = self.create_save_form(form)
|
obj = self.create_save_form(form)
|
||||||
|
Session.flush()
|
||||||
return self.redirect(self.get_action_url('view', obj))
|
return self.redirect(self.get_action_url('view', obj))
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
|
@ -910,7 +911,8 @@ class MasterView(View):
|
||||||
kwargs['columns'] = self.get_grid_columns()
|
kwargs['columns'] = self.get_grid_columns()
|
||||||
|
|
||||||
if 'data' not in kwargs:
|
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:
|
if 'actions' not in kwargs:
|
||||||
actions = []
|
actions = []
|
||||||
|
@ -961,7 +963,7 @@ class MasterView(View):
|
||||||
if hasattr(self, 'grid_columns'):
|
if hasattr(self, 'grid_columns'):
|
||||||
return 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.
|
Returns the grid data for the :meth:`index()` view.
|
||||||
|
|
||||||
|
@ -974,8 +976,27 @@ class MasterView(View):
|
||||||
empty list. Subclass should override as needed.
|
empty list. Subclass should override as needed.
|
||||||
"""
|
"""
|
||||||
query = self.get_query(session=session)
|
query = self.get_query(session=session)
|
||||||
if query is not None:
|
if query:
|
||||||
return query.all()
|
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 []
|
return []
|
||||||
|
|
||||||
|
@ -1131,7 +1152,6 @@ class MasterView(View):
|
||||||
|
|
||||||
kwargs['model_instance'] = model_instance
|
kwargs['model_instance'] = model_instance
|
||||||
|
|
||||||
# if 'fields' not in kwargs:
|
|
||||||
if not kwargs.get('fields'):
|
if not kwargs.get('fields'):
|
||||||
fields = self.get_form_fields()
|
fields = self.get_form_fields()
|
||||||
if fields:
|
if fields:
|
||||||
|
@ -1181,8 +1201,13 @@ class MasterView(View):
|
||||||
already be "complete" and ready to use as-is, but this method
|
already be "complete" and ready to use as-is, but this method
|
||||||
can further modify it based on request details etc.
|
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:
|
if self.editing:
|
||||||
for key in self.get_model_key():
|
for key in model_keys:
|
||||||
form.set_readonly(key)
|
form.set_readonly(key)
|
||||||
|
|
||||||
def objectify(self, form):
|
def objectify(self, form):
|
||||||
|
|
95
src/wuttaweb/views/people.py
Normal file
95
src/wuttaweb/views/people.py
Normal 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)
|
|
@ -26,12 +26,9 @@ Views for app settings
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import colander
|
|
||||||
|
|
||||||
from wuttjamaican.db.model import Setting
|
from wuttjamaican.db.model import Setting
|
||||||
from wuttaweb.views import MasterView
|
from wuttaweb.views import MasterView
|
||||||
from wuttaweb.util import get_libver, get_liburl
|
from wuttaweb.util import get_libver, get_liburl
|
||||||
from wuttaweb.db import Session
|
|
||||||
|
|
||||||
|
|
||||||
class AppInfoView(MasterView):
|
class AppInfoView(MasterView):
|
||||||
|
|
|
@ -36,9 +36,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# subclass may specify
|
# subclass may specify
|
||||||
MyModel = MagicMock()
|
MyModel = MagicMock()
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertIs(master.MasterView.get_model_class(), MyModel)
|
self.assertIs(master.MasterView.get_model_class(), MyModel)
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_model_name(self):
|
def test_get_model_name(self):
|
||||||
|
|
||||||
|
@ -52,9 +52,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Blaster')
|
MyModel = MagicMock(__name__='Blaster')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_model_name(), 'Blaster')
|
self.assertEqual(master.MasterView.get_model_name(), 'Blaster')
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_model_name_normalized(self):
|
def test_get_model_name_normalized(self):
|
||||||
|
|
||||||
|
@ -73,9 +73,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Dinosaur')
|
MyModel = MagicMock(__name__='Dinosaur')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_model_name_normalized(), 'dinosaur')
|
self.assertEqual(master.MasterView.get_model_name_normalized(), 'dinosaur')
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_model_title(self):
|
def test_get_model_title(self):
|
||||||
|
|
||||||
|
@ -94,9 +94,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Dinosaur')
|
MyModel = MagicMock(__name__='Dinosaur')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_model_title(), "Dinosaur")
|
self.assertEqual(master.MasterView.get_model_title(), "Dinosaur")
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_model_title_plural(self):
|
def test_get_model_title_plural(self):
|
||||||
|
|
||||||
|
@ -120,9 +120,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Dinosaur')
|
MyModel = MagicMock(__name__='Dinosaur')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_model_title_plural(), "Dinosaurs")
|
self.assertEqual(master.MasterView.get_model_title_plural(), "Dinosaurs")
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_model_key(self):
|
def test_get_model_key(self):
|
||||||
|
|
||||||
|
@ -156,9 +156,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Truck')
|
MyModel = MagicMock(__name__='Truck')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_route_prefix(), 'trucks')
|
self.assertEqual(master.MasterView.get_route_prefix(), 'trucks')
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_url_prefix(self):
|
def test_get_url_prefix(self):
|
||||||
|
|
||||||
|
@ -187,9 +187,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Machine')
|
MyModel = MagicMock(__name__='Machine')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_url_prefix(), '/machines')
|
self.assertEqual(master.MasterView.get_url_prefix(), '/machines')
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_instance_url_prefix(self):
|
def test_get_instance_url_prefix(self):
|
||||||
|
|
||||||
|
@ -242,9 +242,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Machine')
|
MyModel = MagicMock(__name__='Machine')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_template_prefix(), '/machines')
|
self.assertEqual(master.MasterView.get_template_prefix(), '/machines')
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_grid_key(self):
|
def test_get_grid_key(self):
|
||||||
|
|
||||||
|
@ -273,9 +273,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Machine')
|
MyModel = MagicMock(__name__='Machine')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_grid_key(), 'machines')
|
self.assertEqual(master.MasterView.get_grid_key(), 'machines')
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
def test_get_config_title(self):
|
def test_get_config_title(self):
|
||||||
|
|
||||||
|
@ -304,9 +304,9 @@ class TestMasterView(WebTestCase):
|
||||||
|
|
||||||
# or it may specify model class
|
# or it may specify model class
|
||||||
MyModel = MagicMock(__name__='Dinosaur')
|
MyModel = MagicMock(__name__='Dinosaur')
|
||||||
master.MasterView.model_class = MyModel
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=MyModel):
|
||||||
self.assertEqual(master.MasterView.get_config_title(), "Dinosaurs")
|
self.assertEqual(master.MasterView.get_config_title(), "Dinosaurs")
|
||||||
del master.MasterView.model_class
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# support methods
|
# support methods
|
||||||
|
@ -365,6 +365,28 @@ class TestMasterView(WebTestCase):
|
||||||
grid = view.make_model_grid(session=self.session)
|
grid = view.make_model_grid(session=self.session)
|
||||||
self.assertIs(grid.model_class, model.Setting)
|
self.assertIs(grid.model_class, model.Setting)
|
||||||
|
|
||||||
|
def test_get_grid_data(self):
|
||||||
|
model = self.app.model
|
||||||
|
self.app.save_setting(self.session, 'foo', 'bar')
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
|
# basic logic with Setting model
|
||||||
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=model.Setting):
|
||||||
|
view = master.MasterView(self.request)
|
||||||
|
data = view.get_grid_data(session=self.session)
|
||||||
|
self.assertEqual(len(data), 1)
|
||||||
|
self.assertEqual(data[0], {'name': 'foo', 'value': 'bar'})
|
||||||
|
|
||||||
|
# error if model not known
|
||||||
|
view = master.MasterView(self.request)
|
||||||
|
self.assertFalse(hasattr(master.MasterView, 'model_class'))
|
||||||
|
def get_query(session=None):
|
||||||
|
session = session or self.session
|
||||||
|
return session.query(model.Setting)
|
||||||
|
with patch.object(view, 'get_query', new=get_query):
|
||||||
|
self.assertRaises(ValueError, view.get_grid_data, session=self.session)
|
||||||
|
|
||||||
def test_get_instance(self):
|
def test_get_instance(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
self.app.save_setting(self.session, 'foo', 'bar')
|
self.app.save_setting(self.session, 'foo', 'bar')
|
||||||
|
@ -408,6 +430,19 @@ class TestMasterView(WebTestCase):
|
||||||
form = view.make_model_form()
|
form = view.make_model_form()
|
||||||
self.assertIs(form.model_class, model.Setting)
|
self.assertIs(form.model_class, model.Setting)
|
||||||
|
|
||||||
|
def test_configure_form(self):
|
||||||
|
model = self.app.model
|
||||||
|
|
||||||
|
# uuid field is pruned
|
||||||
|
with patch.multiple(master.MasterView, create=True,
|
||||||
|
model_class=model.Setting):
|
||||||
|
view = master.MasterView(self.request)
|
||||||
|
form = view.make_form(model_class=model.Setting,
|
||||||
|
fields=['uuid', 'name', 'value'])
|
||||||
|
self.assertIn('uuid', form.fields)
|
||||||
|
view.configure_form(form)
|
||||||
|
self.assertNotIn('uuid', form.fields)
|
||||||
|
|
||||||
def test_objectify(self):
|
def test_objectify(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
self.app.save_setting(self.session, 'foo', 'bar')
|
self.app.save_setting(self.session, 'foo', 'bar')
|
||||||
|
|
39
tests/views/test_people.py
Normal file
39
tests/views/test_people.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
|
from pyramid.httpexceptions import HTTPNotFound
|
||||||
|
|
||||||
|
from wuttaweb.views import people
|
||||||
|
from tests.views.utils import WebTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestPersonView(WebTestCase):
|
||||||
|
|
||||||
|
def make_view(self):
|
||||||
|
return people.PersonView(self.request)
|
||||||
|
|
||||||
|
def test_get_query(self):
|
||||||
|
view = self.make_view()
|
||||||
|
query = view.get_query(session=self.session)
|
||||||
|
self.assertIsInstance(query, orm.Query)
|
||||||
|
|
||||||
|
def test_configure_grid(self):
|
||||||
|
model = self.app.model
|
||||||
|
view = self.make_view()
|
||||||
|
grid = view.make_grid(model_class=model.Setting)
|
||||||
|
self.assertEqual(grid.linked_columns, [])
|
||||||
|
view.configure_grid(grid)
|
||||||
|
self.assertIn('full_name', grid.linked_columns)
|
||||||
|
|
||||||
|
def test_configure_form(self):
|
||||||
|
model = self.app.model
|
||||||
|
view = self.make_view()
|
||||||
|
form = view.make_form(model_class=model.Person)
|
||||||
|
form.set_fields(form.get_model_fields())
|
||||||
|
self.assertEqual(form.required_fields, {})
|
||||||
|
view.configure_form(form)
|
||||||
|
self.assertTrue(form.required_fields)
|
||||||
|
self.assertFalse(form.required_fields['middle_name'])
|
Loading…
Reference in a new issue