Add initial versioning support with SQLAlchemy-Continuum.
This commit is contained in:
parent
41dd2ef17b
commit
def466935b
43 changed files with 717 additions and 26 deletions
|
@ -1,9 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2012 Lance Edgar
|
||||
# Copyright © 2010-2015 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -21,15 +20,18 @@
|
|||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
"""
|
||||
Brand Views
|
||||
"""
|
||||
|
||||
from . import SearchableAlchemyGridView, CrudView, AutocompleteView
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import Brand
|
||||
|
||||
from . import SearchableAlchemyGridView, CrudView, AutocompleteView
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
class BrandsGrid(SearchableAlchemyGridView):
|
||||
|
||||
|
@ -81,6 +83,14 @@ class BrandCrud(CrudView):
|
|||
return fs
|
||||
|
||||
|
||||
class BrandVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a brand.
|
||||
"""
|
||||
parent_class = model.Brand
|
||||
route_model_view = 'brand.read'
|
||||
|
||||
|
||||
class BrandsAutocomplete(AutocompleteView):
|
||||
|
||||
mapped_class = Brand
|
||||
|
@ -122,3 +132,5 @@ def includeme(config):
|
|||
config.add_view(BrandCrud, attr='delete',
|
||||
route_name='brand.delete',
|
||||
permission='brands.delete')
|
||||
|
||||
version_defaults(config, BrandVersionView, 'brand')
|
||||
|
|
|
@ -26,9 +26,11 @@ Category Views
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import Category
|
||||
|
||||
from . import SearchableAlchemyGridView, CrudView
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
class CategoriesGrid(SearchableAlchemyGridView):
|
||||
|
@ -85,6 +87,16 @@ class CategoryCrud(CrudView):
|
|||
return fs
|
||||
|
||||
|
||||
class CategoryVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a category.
|
||||
"""
|
||||
parent_class = model.Category
|
||||
model_title_plural = "Categories"
|
||||
route_model_list = 'categories'
|
||||
route_model_view = 'category.read'
|
||||
|
||||
|
||||
def add_routes(config):
|
||||
config.add_route('categories', '/categories')
|
||||
config.add_route('category.create', '/categories/new')
|
||||
|
@ -109,3 +121,5 @@ def includeme(config):
|
|||
renderer='/categories/crud.mako', permission='categories.update')
|
||||
config.add_view(CategoryCrud, attr='delete', route_name='category.delete',
|
||||
permission='categories.delete')
|
||||
|
||||
version_defaults(config, CategoryVersionView, 'category', template_prefix='/categories')
|
||||
|
|
231
tailbone/views/continuum.py
Normal file
231
tailbone/views/continuum.py
Normal file
|
@ -0,0 +1,231 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2015 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Rattail 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 Affero General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Continuum Version Views
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model.continuum import model_transaction_query
|
||||
|
||||
import formalchemy
|
||||
from pyramid.httpexceptions import HTTPNotFound
|
||||
|
||||
from tailbone.db import Session
|
||||
from tailbone.views import PagedAlchemyGridView, View
|
||||
from tailbone.forms import DateTimeFieldRenderer
|
||||
|
||||
|
||||
class VersionView(PagedAlchemyGridView):
|
||||
"""
|
||||
View which shows version history for a model instance.
|
||||
"""
|
||||
|
||||
@property
|
||||
def parent_class(self):
|
||||
"""
|
||||
Model class which is "parent" to the version class.
|
||||
"""
|
||||
raise NotImplementedError("Please set `parent_class` on your `VersionView` subclass.")
|
||||
|
||||
@property
|
||||
def child_classes(self):
|
||||
"""
|
||||
Model class(es) which are "children" to the version's parent class.
|
||||
"""
|
||||
return []
|
||||
|
||||
@property
|
||||
def model_title(self):
|
||||
"""
|
||||
Human-friendly title for the parent model class.
|
||||
"""
|
||||
return self.parent_class.__name__
|
||||
|
||||
@property
|
||||
def model_title_plural(self):
|
||||
"""
|
||||
Plural version of the human-friendly title for the parent model class.
|
||||
"""
|
||||
return '{0}s'.format(self.model_title)
|
||||
|
||||
@property
|
||||
def prefix(self):
|
||||
return self.parent_class.__name__.lower()
|
||||
|
||||
@property
|
||||
def config_prefix(self):
|
||||
return self.prefix
|
||||
|
||||
@property
|
||||
def transaction_class(self):
|
||||
return continuum.transaction_class(self.parent_class)
|
||||
|
||||
@property
|
||||
def mapped_class(self):
|
||||
return self.transaction_class
|
||||
|
||||
@property
|
||||
def version_class(self):
|
||||
return continuum.version_class(self.parent_class)
|
||||
|
||||
@property
|
||||
def route_model_list(self):
|
||||
return '{0}s'.format(self.prefix)
|
||||
|
||||
@property
|
||||
def route_model_view(self):
|
||||
return self.prefix
|
||||
|
||||
def join_map(self):
|
||||
return {
|
||||
'user':
|
||||
lambda q: q.outerjoin(model.User, self.transaction_class.user_uuid == model.User.uuid),
|
||||
}
|
||||
|
||||
def sort_config(self):
|
||||
return self.make_sort_config(sort='issued_at', dir='desc')
|
||||
|
||||
def sort_map(self):
|
||||
return self.make_sort_map('issued_at', 'remote_addr',
|
||||
user=self.sorter(model.User.username))
|
||||
|
||||
def transaction_query(self, session=Session):
|
||||
uuid = self.request.matchdict['uuid']
|
||||
return model_transaction_query(session, uuid, self.parent_class,
|
||||
child_classes=self.child_classes)
|
||||
|
||||
def make_query(self, session=Session):
|
||||
query = self.transaction_query(session)
|
||||
return self.modify_query(query)
|
||||
|
||||
def grid(self):
|
||||
g = self.make_grid()
|
||||
g.issued_at.set(renderer=DateTimeFieldRenderer(self.request.rattail_config))
|
||||
g.configure(
|
||||
include=[
|
||||
g.issued_at.label("When"),
|
||||
g.user.label("Who"),
|
||||
g.remote_addr.label("Client IP"),
|
||||
],
|
||||
readonly=True)
|
||||
g.viewable = True
|
||||
g.view_route_name = '{0}.version'.format(self.prefix)
|
||||
g.view_route_kwargs = self.view_route_kwargs
|
||||
return g
|
||||
|
||||
def render_kwargs(self):
|
||||
instance = Session.query(self.parent_class).get(self.request.matchdict['uuid'])
|
||||
return {'model_title': self.model_title,
|
||||
'model_title_plural': self.model_title_plural,
|
||||
'model_instance': instance,
|
||||
'route_model_list': self.route_model_list,
|
||||
'route_model_view': self.route_model_view}
|
||||
|
||||
def view_route_kwargs(self, transaction):
|
||||
return {'uuid': self.request.matchdict['uuid'],
|
||||
'transaction_id': transaction.id}
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
View which shows the version history list for a model instance.
|
||||
"""
|
||||
return self()
|
||||
|
||||
def details(self):
|
||||
"""
|
||||
View which shows the change details of a model version.
|
||||
"""
|
||||
kwargs = self.render_kwargs()
|
||||
uuid = self.request.matchdict['uuid']
|
||||
transaction_id = self.request.matchdict['transaction_id']
|
||||
transaction = Session.query(self.transaction_class).get(transaction_id)
|
||||
if not transaction:
|
||||
raise HTTPNotFound
|
||||
|
||||
version = Session.query(self.version_class).get((uuid, transaction_id))
|
||||
|
||||
def normalize_child_classes():
|
||||
classes = []
|
||||
for cls in self.child_classes:
|
||||
if not isinstance(cls, tuple):
|
||||
cls = (cls, 'uuid')
|
||||
classes.append(cls)
|
||||
return classes
|
||||
|
||||
versions = []
|
||||
if version:
|
||||
versions.append(version)
|
||||
for model_class, attr in normalize_child_classes():
|
||||
if isinstance(model_class, type) and issubclass(model_class, model.Base):
|
||||
cls = continuum.version_class(model_class)
|
||||
ver = Session.query(cls).filter_by(transaction_id=transaction_id, **{attr: uuid}).first()
|
||||
if ver:
|
||||
versions.append(ver)
|
||||
|
||||
previous_transaction = self.transaction_query()\
|
||||
.order_by(self.transaction_class.id.desc())\
|
||||
.filter(self.transaction_class.id < transaction.id)\
|
||||
.first()
|
||||
|
||||
next_transaction = self.transaction_query()\
|
||||
.order_by(self.transaction_class.id.asc())\
|
||||
.filter(self.transaction_class.id > transaction.id)\
|
||||
.first()
|
||||
|
||||
kwargs.update({
|
||||
'route_prefix': self.prefix,
|
||||
'version': version,
|
||||
'transaction': transaction,
|
||||
'versions': versions,
|
||||
'parent_class': continuum.parent_class,
|
||||
'previous_transaction': previous_transaction,
|
||||
'next_transaction': next_transaction,
|
||||
})
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def version_defaults(config, VersionView, prefix, template_prefix=None):
|
||||
"""
|
||||
Apply default route/view configuration for the given ``VersionView``.
|
||||
"""
|
||||
if template_prefix is None:
|
||||
template_prefix = '/{0}s'.format(prefix)
|
||||
template_prefix = template_prefix.rstrip('/')
|
||||
|
||||
# list changesets
|
||||
config.add_route('{0}.versions'.format(prefix), '/{0}/{{uuid}}/changesets/'.format(prefix))
|
||||
config.add_view(VersionView, attr='list', route_name='{0}.versions'.format(prefix),
|
||||
renderer='{0}/versions/index.mako'.format(template_prefix),
|
||||
permission='{0}.versions.view'.format(prefix))
|
||||
|
||||
# view changeset
|
||||
config.add_route('{0}.version'.format(prefix), '/{0}/{{uuid}}/changeset/{{transaction_id}}'.format(prefix))
|
||||
config.add_view(VersionView, attr='details', route_name='{0}.version'.format(prefix),
|
||||
renderer='{0}/versions/view.mako'.format(template_prefix),
|
||||
permission='{0}.versions.view'.format(prefix))
|
|
@ -32,16 +32,23 @@ except ImportError:
|
|||
inspect = None
|
||||
from sqlalchemy.orm import class_mapper
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy_continuum import transaction_class, version_class
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model.continuum import count_versions, model_transaction_query
|
||||
|
||||
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
||||
|
||||
from .core import View
|
||||
|
||||
from ..forms import AlchemyForm
|
||||
from formalchemy import FieldSet
|
||||
from ..db import Session
|
||||
|
||||
from edbob.util import prettify
|
||||
|
||||
from tailbone.db import Session
|
||||
|
||||
|
||||
__all__ = ['CrudView']
|
||||
|
||||
|
@ -51,6 +58,7 @@ class CrudView(View):
|
|||
readonly = False
|
||||
allow_successive_creates = False
|
||||
update_cancel_route = None
|
||||
child_version_classes = []
|
||||
|
||||
@property
|
||||
def mapped_class(self):
|
||||
|
@ -161,7 +169,21 @@ class CrudView(View):
|
|||
pass
|
||||
|
||||
def template_kwargs(self, form):
|
||||
return {}
|
||||
if form.creating:
|
||||
return {}
|
||||
return {'version_count': self.count_versions()}
|
||||
|
||||
def count_versions(self):
|
||||
query = self.transaction_query()
|
||||
return query.count()
|
||||
|
||||
def transaction_query(self, parent_class=None, child_classes=None):
|
||||
uuid = self.request.matchdict['uuid']
|
||||
if parent_class is None:
|
||||
parent_class = self.mapped_class
|
||||
if child_classes is None:
|
||||
child_classes = self.child_version_classes
|
||||
return model_transaction_query(Session, uuid, parent_class, child_classes=child_classes)
|
||||
|
||||
def post_save(self, form):
|
||||
pass
|
||||
|
|
|
@ -26,9 +26,11 @@ Department Views
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import Department, Product, ProductCost, Vendor
|
||||
|
||||
from . import SearchableAlchemyGridView, CrudView, AlchemyGridView, AutocompleteView
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
class DepartmentsGrid(SearchableAlchemyGridView):
|
||||
|
@ -83,6 +85,14 @@ class DepartmentCrud(CrudView):
|
|||
return fs
|
||||
|
||||
|
||||
class DepartmentVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a department.
|
||||
"""
|
||||
parent_class = model.Department
|
||||
route_model_view = 'department.read'
|
||||
|
||||
|
||||
class DepartmentsByVendorGrid(AlchemyGridView):
|
||||
|
||||
mapped_class = Department
|
||||
|
@ -150,3 +160,5 @@ def includeme(config):
|
|||
renderer='/departments/crud.mako', permission='departments.update')
|
||||
config.add_view(DepartmentCrud, attr='delete', route_name='department.delete',
|
||||
permission='departments.delete')
|
||||
|
||||
version_defaults(config, DepartmentVersionView, 'department')
|
||||
|
|
|
@ -26,6 +26,9 @@ Label Views
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import LabelProfile
|
||||
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
import formalchemy
|
||||
|
@ -36,7 +39,7 @@ from ..db import Session
|
|||
from . import SearchableAlchemyGridView, CrudView
|
||||
from ..grids.search import BooleanSearchFilter
|
||||
|
||||
from rattail.db.model import LabelProfile
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
class ProfilesGrid(SearchableAlchemyGridView):
|
||||
|
@ -129,6 +132,16 @@ class ProfileCrud(CrudView):
|
|||
uuid=form.fieldset.model.uuid)
|
||||
|
||||
|
||||
class LabelProfileVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a label profile.
|
||||
"""
|
||||
parent_class = model.LabelProfile
|
||||
model_title = "Label Profile"
|
||||
route_model_list = 'label_profiles'
|
||||
route_model_view = 'label_profile.read'
|
||||
|
||||
|
||||
def printer_settings(request):
|
||||
uuid = request.matchdict['uuid']
|
||||
profile = Session.query(LabelProfile).get(uuid) if uuid else None
|
||||
|
@ -187,3 +200,5 @@ def includeme(config):
|
|||
config.add_view(printer_settings, route_name='label_profile.printer_settings',
|
||||
renderer='/labels/profiles/printer.mako',
|
||||
permission='label_profiles.update')
|
||||
|
||||
version_defaults(config, LabelProfileVersionView, 'labelprofile', template_prefix='/labels/profiles')
|
||||
|
|
|
@ -56,6 +56,7 @@ from rattail.pod import get_image_url, get_image_path
|
|||
from ..db import Session
|
||||
from ..forms import GPCFieldRenderer, BrandFieldRenderer, PriceFieldRenderer
|
||||
from . import CrudView
|
||||
from .continuum import VersionView, version_defaults
|
||||
from ..progress import SessionProgress
|
||||
|
||||
|
||||
|
@ -237,9 +238,16 @@ class ProductsGrid(SearchableAlchemyGridView):
|
|||
|
||||
|
||||
class ProductCrud(CrudView):
|
||||
|
||||
"""
|
||||
Product CRUD view class.
|
||||
"""
|
||||
mapped_class = Product
|
||||
home_route = 'products'
|
||||
child_version_classes = [
|
||||
(model.ProductCode, 'product_uuid'),
|
||||
(model.ProductCost, 'product_uuid'),
|
||||
(model.ProductPrice, 'product_uuid'),
|
||||
]
|
||||
|
||||
def get_model(self, key):
|
||||
model = super(ProductCrud, self).get_model(key)
|
||||
|
@ -277,7 +285,8 @@ class ProductCrud(CrudView):
|
|||
return fs
|
||||
|
||||
def template_kwargs(self, form):
|
||||
kwargs = {'image': False}
|
||||
kwargs = super(ProductCrud, self).template_kwargs(form)
|
||||
kwargs['image'] = False
|
||||
product = form.fieldset.model
|
||||
if product.upc:
|
||||
kwargs['image_url'] = get_image_url(
|
||||
|
@ -289,6 +298,19 @@ class ProductCrud(CrudView):
|
|||
return kwargs
|
||||
|
||||
|
||||
class ProductVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a product.
|
||||
"""
|
||||
parent_class = model.Product
|
||||
route_model_view = 'product.read'
|
||||
child_classes = [
|
||||
(model.ProductCode, 'product_uuid'),
|
||||
(model.ProductCost, 'product_uuid'),
|
||||
(model.ProductPrice, 'product_uuid'),
|
||||
]
|
||||
|
||||
|
||||
def products_search(request):
|
||||
"""
|
||||
Locate a product(s) by UPC.
|
||||
|
@ -443,3 +465,5 @@ def includeme(config):
|
|||
permission='products.delete')
|
||||
config.add_view(products_search, route_name='products.search',
|
||||
renderer='json', permission='products.list')
|
||||
|
||||
version_defaults(config, ProductVersionView, 'product')
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
Role Views
|
||||
"""
|
||||
|
||||
from rattail.db import model
|
||||
|
||||
from . import SearchableAlchemyGridView, CrudView
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
|
@ -37,6 +39,8 @@ import formalchemy
|
|||
from webhelpers.html import tags
|
||||
from webhelpers.html import HTML
|
||||
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
default_permissions = [
|
||||
("Batches", [
|
||||
|
@ -264,6 +268,14 @@ class RoleCrud(CrudView):
|
|||
return HTTPFound(location=self.request.get_referrer())
|
||||
|
||||
|
||||
class RoleVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a role.
|
||||
"""
|
||||
parent_class = model.Role
|
||||
route_model_view = 'role.read'
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
||||
config.add_route('roles', '/roles')
|
||||
|
@ -294,3 +306,5 @@ def includeme(config):
|
|||
config.add_route('role.delete', '/roles/{uuid}/delete')
|
||||
config.add_view(RoleCrud, attr='delete', route_name='role.delete',
|
||||
permission='roles.delete')
|
||||
|
||||
version_defaults(config, RoleVersionView, 'role')
|
||||
|
|
|
@ -26,9 +26,11 @@ Subdepartment Views
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import Subdepartment
|
||||
|
||||
from . import SearchableAlchemyGridView, CrudView
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
class SubdepartmentsGrid(SearchableAlchemyGridView):
|
||||
|
@ -85,6 +87,14 @@ class SubdepartmentCrud(CrudView):
|
|||
return fs
|
||||
|
||||
|
||||
class SubdepartmentVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a subdepartment.
|
||||
"""
|
||||
parent_class = model.Subdepartment
|
||||
route_model_view = 'subdepartment.read'
|
||||
|
||||
|
||||
def add_routes(config):
|
||||
config.add_route('subdepartments', '/subdepartments')
|
||||
config.add_route('subdepartment.create', '/subdepartments/new')
|
||||
|
@ -109,3 +119,5 @@ def includeme(config):
|
|||
renderer='/subdepartments/crud.mako', permission='subdepartments.update')
|
||||
config.add_view(SubdepartmentCrud, attr='delete', route_name='subdepartment.delete',
|
||||
permission='subdepartments.delete')
|
||||
|
||||
version_defaults(config, SubdepartmentVersionView, 'subdepartment')
|
||||
|
|
|
@ -26,6 +26,7 @@ User Views
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import User, Person, Role
|
||||
from rattail.db.auth import guest_role, set_user_password
|
||||
|
||||
|
@ -40,6 +41,8 @@ from ..forms import PersonFieldLinkRenderer
|
|||
from ..db import Session
|
||||
from tailbone.grids.search import BooleanSearchFilter
|
||||
|
||||
from .continuum import VersionView, version_defaults
|
||||
|
||||
|
||||
class UsersGrid(SearchableAlchemyGridView):
|
||||
|
||||
|
@ -205,6 +208,14 @@ class UserCrud(CrudView):
|
|||
return fs
|
||||
|
||||
|
||||
class UserVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a user.
|
||||
"""
|
||||
parent_class = model.User
|
||||
route_model_view = 'user.read'
|
||||
|
||||
|
||||
def add_routes(config):
|
||||
config.add_route(u'users', u'/users')
|
||||
config.add_route(u'user.create', u'/users/new')
|
||||
|
@ -233,3 +244,5 @@ def includeme(config):
|
|||
permission='users.update')
|
||||
config.add_view(UserCrud, attr='delete', route_name='user.delete',
|
||||
permission='users.delete')
|
||||
|
||||
version_defaults(config, UserVersionView, 'user')
|
||||
|
|
3
tailbone/views/vendors/__init__.py
vendored
3
tailbone/views/vendors/__init__.py
vendored
|
@ -26,7 +26,8 @@ Views pertaining to vendors
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .core import VendorsGrid, VendorCrud, VendorsAutocomplete, add_routes
|
||||
from .core import (VendorsGrid, VendorCrud, VendorVersionView,
|
||||
VendorsAutocomplete, add_routes)
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
|
25
tailbone/views/vendors/core.py
vendored
25
tailbone/views/vendors/core.py
vendored
|
@ -1,9 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2012 Lance Edgar
|
||||
# Copyright © 2010-2015 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -21,15 +20,19 @@
|
|||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
"""
|
||||
Vendor Views
|
||||
"""
|
||||
|
||||
from tailbone.views import SearchableAlchemyGridView, CrudView, AutocompleteView
|
||||
from tailbone.forms import AssociationProxyField, PersonFieldRenderer
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import Vendor
|
||||
|
||||
from tailbone.views import SearchableAlchemyGridView, CrudView, AutocompleteView
|
||||
from tailbone.views.continuum import VersionView, version_defaults
|
||||
from tailbone.forms import AssociationProxyField, PersonFieldRenderer
|
||||
|
||||
|
||||
class VendorsGrid(SearchableAlchemyGridView):
|
||||
|
||||
|
@ -93,6 +96,14 @@ class VendorCrud(CrudView):
|
|||
return fs
|
||||
|
||||
|
||||
class VendorVersionView(VersionView):
|
||||
"""
|
||||
View which shows version history for a vendor.
|
||||
"""
|
||||
parent_class = model.Vendor
|
||||
route_model_view = 'vendor.read'
|
||||
|
||||
|
||||
class VendorsAutocomplete(AutocompleteView):
|
||||
|
||||
mapped_class = Vendor
|
||||
|
@ -127,3 +138,5 @@ def includeme(config):
|
|||
permission='vendors.update')
|
||||
config.add_view(VendorCrud, attr='delete', route_name='vendor.delete',
|
||||
permission='vendors.delete')
|
||||
|
||||
version_defaults(config, VendorVersionView, 'vendor')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue