Convert 'people' view to use MasterView pattern.

This commit is contained in:
Lance Edgar 2015-12-06 18:04:23 -06:00
parent 717a614194
commit fee00b96a2
5 changed files with 62 additions and 139 deletions

View file

@ -29,7 +29,7 @@ from formencode import Schema
from .core import Form, Field, FieldSet from .core import Form, Field, FieldSet
from .simpleform import SimpleForm, FormRenderer from .simpleform import SimpleForm, FormRenderer
from .alchemy import AlchemyForm from .alchemy import AlchemyForm
from .fields import * from .fields import AssociationProxyField
from .renderers import * from .renderers import *
from tailbone.forms import renderers from tailbone.forms import renderers

View file

@ -1,9 +1,8 @@
#!/usr/bin/env python # -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2012 Lance Edgar # Copyright © 2010-2015 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -21,17 +20,15 @@
# along with Rattail. If not, see <http://www.gnu.org/licenses/>. # along with Rattail. If not, see <http://www.gnu.org/licenses/>.
# #
################################################################################ ################################################################################
"""
FormAlchemy Fields
"""
""" from __future__ import unicode_literals, absolute_import
``tailbone.forms.fields`` -- FormAlchemy Fields
"""
from formalchemy import Field from formalchemy import Field
__all__ = ['AssociationProxyField']
def AssociationProxyField(name, **kwargs): def AssociationProxyField(name, **kwargs):
""" """
Returns a FormAlchemy ``Field`` class which is aware of association Returns a FormAlchemy ``Field`` class which is aware of association

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to People", url('people'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Person", url('person.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Person", url('person.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">People</%def>
<%def name="context_menu_items()">
## % if request.has_perm('people.create'):
## <li>${h.link_to("Create a new Person", url('person.new'))}</li>
## % endif
</%def>
${parent.body()}

View file

@ -1,9 +1,8 @@
#!/usr/bin/env python # -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2012 Lance Edgar # Copyright © 2010-2015 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -21,63 +20,53 @@
# along with Rattail. If not, see <http://www.gnu.org/licenses/>. # along with Rattail. If not, see <http://www.gnu.org/licenses/>.
# #
################################################################################ ################################################################################
""" """
Person Views Person Views
""" """
from sqlalchemy import and_ from __future__ import unicode_literals, absolute_import
from . import SearchableAlchemyGridView, CrudView, AutocompleteView import sqlalchemy as sa
from ..db import Session from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from tailbone.views import MasterView, AutocompleteView
from rattail.db import model from rattail.db import model
from rattail.db.model import (Person, PersonEmailAddress, PersonPhoneNumber,
VendorContact)
class PeopleGrid(SearchableAlchemyGridView): class PeopleView(MasterView):
"""
Master view for the Person class.
"""
model_class = model.Person
model_title_plural = "People"
route_prefix = 'people'
mapped_class = Person def configure_grid(self, g):
config_prefix = 'people' g.joiners['email'] = lambda q: q.outerjoin(model.PersonEmailAddress, sa.and_(
sort = 'display_name' model.PersonEmailAddress.parent_uuid == model.Person.uuid,
model.PersonEmailAddress.preference == 1))
g.joiners['phone'] = lambda q: q.outerjoin(model.PersonPhoneNumber, sa.and_(
model.PersonPhoneNumber.parent_uuid == model.Person.uuid,
model.PersonPhoneNumber.preference == 1))
def join_map(self): g.filters['email'] = g.make_filter('email', model.PersonEmailAddress.address,
return { label="Email Address")
'email': g.filters['phone'] = g.make_filter('phone', model.PersonPhoneNumber.number,
lambda q: q.outerjoin(PersonEmailAddress, and_( label="Phone Number")
PersonEmailAddress.parent_uuid == Person.uuid,
PersonEmailAddress.preference == 1)),
'phone':
lambda q: q.outerjoin(PersonPhoneNumber, and_(
PersonPhoneNumber.parent_uuid == Person.uuid,
PersonPhoneNumber.preference == 1)),
}
def filter_map(self): g.filters['first_name'].default_active = True
return self.make_filter_map( g.filters['first_name'].default_verb = 'contains'
ilike=['first_name', 'last_name', 'display_name'],
email=self.filter_ilike(PersonEmailAddress.address),
phone=self.filter_ilike(PersonPhoneNumber.number))
def filter_config(self): g.filters['last_name'].default_active = True
return self.make_filter_config( g.filters['last_name'].default_verb = 'contains'
include_filter_first_name=True,
filter_type_first_name='lk',
include_filter_last_name=True,
filter_type_last_name='lk',
filter_label_phone="Phone Number",
filter_label_email="Email Address")
def sort_map(self): g.sorters['email'] = lambda q, d: q.order_by(getattr(model.PersonEmailAddress.address, d)())
return self.make_sort_map( g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.PersonPhoneNumber.number, d)())
'first_name', 'last_name', 'display_name',
email=self.sorter(PersonEmailAddress.address), g.default_sortkey = 'display_name'
phone=self.sorter(PersonPhoneNumber.number))
def grid(self):
g = self.make_grid()
g.configure( g.configure(
include=[ include=[
g.first_name, g.first_name,
@ -85,38 +74,22 @@ class PeopleGrid(SearchableAlchemyGridView):
g.display_name, g.display_name,
g.phone.label("Phone Number"), g.phone.label("Phone Number"),
g.email.label("Email Address"), g.email.label("Email Address"),
], ],
readonly=True) readonly=True)
if self.request.has_perm('people.read'): def get_instance(self):
g.viewable = True # TODO: I don't recall why this fallback check for a vendor contact
g.view_route_name = 'person.read' # exists here, but leaving it intact for now.
if self.request.has_perm('people.update'): key = self.request.matchdict['uuid']
g.editable = True instance = self.Session.query(model.Person).get(key)
g.edit_route_name = 'person.update' if instance:
# if self.request.has_perm('products.delete'): return instance
# g.deletable = True instance = self.Session.query(model.VendorContact).get(key)
# g.delete_route_name = 'product.delete' if instance:
return instance.person
raise HTTPNotFound
return g def configure_fieldset(self, fs):
class PersonCrud(CrudView):
mapped_class = Person
home_route = 'people'
def get_model(self, key):
model = super(PersonCrud, self).get_model(key)
if model:
return model
model = Session.query(VendorContact).get(key)
if model:
return model.person
return None
def fieldset(self, model):
fs = self.make_fieldset(model)
fs.configure( fs.configure(
include=[ include=[
fs.first_name, fs.first_name,
@ -124,13 +97,12 @@ class PersonCrud(CrudView):
fs.display_name, fs.display_name,
fs.phone.label("Phone Number").readonly(), fs.phone.label("Phone Number").readonly(),
fs.email.label("Email Address").readonly(), fs.email.label("Email Address").readonly(),
]) ])
return fs
class PeopleAutocomplete(AutocompleteView): class PeopleAutocomplete(AutocompleteView):
mapped_class = Person mapped_class = model.Person
fieldname = 'display_name' fieldname = 'display_name'
@ -144,34 +116,13 @@ class PeopleEmployeesAutocomplete(PeopleAutocomplete):
return q.join(model.Employee) return q.join(model.Employee)
def add_routes(config):
config.add_route('people', '/people')
config.add_route('people.autocomplete', '/people/autocomplete')
config.add_route(u'people.autocomplete.employees', u'/people/autocomplete/employees')
config.add_route('person.read', '/people/{uuid}')
config.add_route('person.update', '/people/{uuid}/edit')
def includeme(config): def includeme(config):
add_routes(config) PeopleView.defaults(config)
# List # autocomplete
config.add_view(PeopleGrid, route_name='people', config.add_route('people.autocomplete', '/people/autocomplete')
renderer='/people/index.mako',
permission='people.list')
# CRUD
config.add_view(PersonCrud, attr='read', route_name='person.read',
renderer='/people/crud.mako',
permission='people.read')
config.add_view(PersonCrud, attr='update', route_name='person.update',
renderer='/people/crud.mako',
permission='people.update')
# Autocomplete
config.add_view(PeopleAutocomplete, route_name='people.autocomplete', config.add_view(PeopleAutocomplete, route_name='people.autocomplete',
renderer='json', renderer='json', permission='people.list')
permission='people.list') config.add_route('people.autocomplete.employees', '/people/autocomplete/employees')
config.add_view(PeopleEmployeesAutocomplete, route_name=u'people.autocomplete.employees', config.add_view(PeopleEmployeesAutocomplete, route_name='people.autocomplete.employees',
renderer=u'json', renderer='json', permission='people.list')
permission=u'people.list')