Add feature to generate new features...
at least that's the idea. probably requires a web UI to be useful
This commit is contained in:
parent
fd043c4c2f
commit
37eb1ec564
|
@ -1,4 +1,4 @@
|
||||||
# -*- mode: conf -*-
|
# -*- mode: conf; -*-
|
||||||
|
|
||||||
include *.cfg
|
include *.cfg
|
||||||
include *.txt
|
include *.txt
|
||||||
|
@ -15,4 +15,4 @@ include rattail/db/alembic/README
|
||||||
recursive-include rattail/db/alembic *.mako
|
recursive-include rattail/db/alembic *.mako
|
||||||
recursive-include rattail/db/alembic *.py
|
recursive-include rattail/db/alembic *.py
|
||||||
|
|
||||||
recursive-include rattail/templates/mail *.mako
|
recursive-include rattail/templates *.mako
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2020 Lance Edgar
|
# Copyright © 2010-2021 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -64,6 +64,12 @@ class AppHandler(object):
|
||||||
self.employment_handler = get_employment_handler(self.config, **kwargs)
|
self.employment_handler = get_employment_handler(self.config, **kwargs)
|
||||||
return self.employment_handler
|
return self.employment_handler
|
||||||
|
|
||||||
|
def get_feature_handler(self, **kwargs):
|
||||||
|
if not hasattr(self, 'feature_handler'):
|
||||||
|
from rattail.features import FeatureHandler
|
||||||
|
self.feature_handler = FeatureHandler(self.config, **kwargs)
|
||||||
|
return self.feature_handler
|
||||||
|
|
||||||
def get_report_handler(self, **kwargs):
|
def get_report_handler(self, **kwargs):
|
||||||
if not hasattr(self, 'report_handler'):
|
if not hasattr(self, 'report_handler'):
|
||||||
from rattail.reporting import get_report_handler
|
from rattail.reporting import get_report_handler
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2020 Lance Edgar
|
# Copyright © 2010-2021 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -374,6 +374,14 @@ class RattailConfig(object):
|
||||||
self.app = make_app(self)
|
self.app = make_app(self)
|
||||||
return self.app
|
return self.app
|
||||||
|
|
||||||
|
def app_package(self, default=None):
|
||||||
|
"""
|
||||||
|
Returns the name of Python package for the top-level app.
|
||||||
|
"""
|
||||||
|
if not default:
|
||||||
|
return self.require('rattail', 'app_package')
|
||||||
|
return self.get('rattail', 'app_package', default=default)
|
||||||
|
|
||||||
def app_title(self, default=None):
|
def app_title(self, default=None):
|
||||||
"""
|
"""
|
||||||
Returns official display title for the current app.
|
Returns official display title for the current app.
|
||||||
|
|
30
rattail/features/__init__.py
Normal file
30
rattail/features/__init__.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 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 General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Generating Features
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
from .base import Feature
|
||||||
|
from .handlers import FeatureHandler
|
61
rattail/features/base.py
Normal file
61
rattail/features/base.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 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 General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Features
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
from mako.lookup import TemplateLookup
|
||||||
|
|
||||||
|
from rattail.files import resource_path
|
||||||
|
|
||||||
|
|
||||||
|
class Feature(object):
|
||||||
|
"""
|
||||||
|
Base class for features.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config):
|
||||||
|
self.config = config
|
||||||
|
|
||||||
|
# TODO: make templates dir configurable
|
||||||
|
templates = [resource_path('rattail:templates/feature')]
|
||||||
|
self.templates = TemplateLookup(directories=templates)
|
||||||
|
|
||||||
|
def get_defaults(self):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_template(self, path):
|
||||||
|
"""
|
||||||
|
Locate and return the given Mako feature template.
|
||||||
|
"""
|
||||||
|
return self.templates.get_template(path)
|
||||||
|
|
||||||
|
def generate_mako(self, template, **context):
|
||||||
|
"""
|
||||||
|
Generate and return output from the given template.
|
||||||
|
"""
|
||||||
|
template = self.get_template(template)
|
||||||
|
text = template.render(**context)
|
||||||
|
return text
|
91
rattail/features/handlers.py
Normal file
91
rattail/features/handlers.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 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 General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Handler for Generating Features
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
import colander
|
||||||
|
|
||||||
|
from rattail.app import GenericHandler
|
||||||
|
from rattail.util import load_entry_points
|
||||||
|
|
||||||
|
|
||||||
|
class FeatureHandler(GenericHandler):
|
||||||
|
"""
|
||||||
|
Base class for feature handlers.
|
||||||
|
"""
|
||||||
|
entry_point_section = 'rattail.features'
|
||||||
|
|
||||||
|
def all_features(self):
|
||||||
|
"""
|
||||||
|
Returns a dict of available features, which are registered via
|
||||||
|
setuptools entry points.
|
||||||
|
"""
|
||||||
|
return load_entry_points(self.entry_point_section)
|
||||||
|
|
||||||
|
def all_feature_types(self):
|
||||||
|
"""
|
||||||
|
Returns a list of available feature type keys.
|
||||||
|
"""
|
||||||
|
return list(self.all_features())
|
||||||
|
|
||||||
|
def iter_features(self):
|
||||||
|
"""
|
||||||
|
Iterate over all features.
|
||||||
|
"""
|
||||||
|
for factory in six.itervalues(self.all_features()):
|
||||||
|
yield factory(self.config)
|
||||||
|
|
||||||
|
def get_feature(self, key):
|
||||||
|
"""
|
||||||
|
Returns the specific feature identified by type key.
|
||||||
|
"""
|
||||||
|
features = self.all_features()
|
||||||
|
if key in features:
|
||||||
|
return features[key](self.config)
|
||||||
|
|
||||||
|
def make_schema(self, **kwargs):
|
||||||
|
|
||||||
|
class Schema(colander.MappingSchema):
|
||||||
|
|
||||||
|
app_prefix = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
app_cap_prefix = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
return Schema(**kwargs)
|
||||||
|
|
||||||
|
def get_defaults(self):
|
||||||
|
return {
|
||||||
|
'app_prefix': self.config.app_title().lower(),
|
||||||
|
'app_cap_prefix': self.config.app_title(),
|
||||||
|
}
|
||||||
|
|
||||||
|
def do_generate(self, feature, **kwargs):
|
||||||
|
"""
|
||||||
|
Generate code and instructions for new feature.
|
||||||
|
"""
|
||||||
|
return feature.generate(**kwargs)
|
66
rattail/features/newreport.py
Normal file
66
rattail/features/newreport.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 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 General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
New Report Feature
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from rattail.features import Feature
|
||||||
|
|
||||||
|
import colander
|
||||||
|
|
||||||
|
|
||||||
|
class NewReportFeature(Feature):
|
||||||
|
"""
|
||||||
|
New Report Feature
|
||||||
|
"""
|
||||||
|
feature_key = 'new-report'
|
||||||
|
feature_title = "New Report"
|
||||||
|
|
||||||
|
def make_schema(self, **kwargs):
|
||||||
|
|
||||||
|
class Schema(colander.MappingSchema):
|
||||||
|
|
||||||
|
name = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
description = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
return Schema(**kwargs)
|
||||||
|
|
||||||
|
def get_defaults(self):
|
||||||
|
return {
|
||||||
|
'name': "Latest Widgets",
|
||||||
|
'description': "Shows all the latest widgets.",
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate(self, **kwargs):
|
||||||
|
context = dict(kwargs)
|
||||||
|
context['app_package'] = self.config.app_package()
|
||||||
|
context['app_slug'] = context['app_package'] # TODO
|
||||||
|
context['code_name'] = re.sub(r'[\s-]', '_', context['name']).lower()
|
||||||
|
context['cap_name'] = context['name'].replace(' ', '')
|
||||||
|
|
||||||
|
return self.generate_mako('/new-report/instructions.mako', **context)
|
79
rattail/features/newtable.py
Normal file
79
rattail/features/newtable.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 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 General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
New Table Feature
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
from rattail.features import Feature
|
||||||
|
|
||||||
|
import colander
|
||||||
|
|
||||||
|
|
||||||
|
class NewTableFeature(Feature):
|
||||||
|
"""
|
||||||
|
New Table Feature
|
||||||
|
"""
|
||||||
|
feature_key = 'new-table'
|
||||||
|
feature_title = "New Table"
|
||||||
|
|
||||||
|
def make_schema(self, **kwargs):
|
||||||
|
|
||||||
|
class Schema(colander.MappingSchema):
|
||||||
|
|
||||||
|
table_name = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
model_name = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
model_title = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
model_title_plural = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
description = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
|
versioned = colander.SchemaNode(colander.Boolean())
|
||||||
|
|
||||||
|
return Schema(**kwargs)
|
||||||
|
|
||||||
|
def get_defaults(self):
|
||||||
|
return {
|
||||||
|
'table_name': 'latest_widget',
|
||||||
|
'model_name': 'LatestWidget',
|
||||||
|
'model_title': "Latest Widget",
|
||||||
|
'model_title_plural': "Latest Widgets",
|
||||||
|
'description': "Represents a Latest Widget.",
|
||||||
|
'versioned': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate(self, **kwargs):
|
||||||
|
context = dict(kwargs)
|
||||||
|
context['app_package'] = self.config.app_package()
|
||||||
|
context['app_slug'] = context['app_package'] # TODO
|
||||||
|
context['envroot'] = '/srv/envs/{}'.format(context['app_slug']) # TODO
|
||||||
|
context['prefixed_table_name'] = '{}_{}'.format(
|
||||||
|
context['app_prefix'], context['table_name'])
|
||||||
|
context['prefixed_model_name'] = '{}{}'.format(
|
||||||
|
context['app_cap_prefix'], context['model_name'])
|
||||||
|
|
||||||
|
return self.generate_mako('/new-table/instructions.mako', **context)
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2020 Lance Edgar
|
# Copyright © 2010-2021 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -24,6 +24,8 @@
|
||||||
Handler for Generating Projects
|
Handler for Generating Projects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
62
rattail/templates/feature/new-report/instructions.mako
Normal file
62
rattail/templates/feature/new-report/instructions.mako
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
## -*- mode: markdown; -*-
|
||||||
|
# New Report: ${name}
|
||||||
|
|
||||||
|
Create a new Python module under `${app_package}.reports`, for instance at
|
||||||
|
`~/src/${app_slug}/${app_package}/reports/${code_name}.py`, with contents:
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
"${name}" report
|
||||||
|
"""
|
||||||
|
|
||||||
|
# from sqlalchemy import orm
|
||||||
|
|
||||||
|
from rattail.reporting import ExcelReport
|
||||||
|
|
||||||
|
from ${app_package}.db import model
|
||||||
|
|
||||||
|
|
||||||
|
class ${cap_name}(ExcelReport):
|
||||||
|
"""
|
||||||
|
${description}
|
||||||
|
"""
|
||||||
|
type_key = '${app_prefix}_${code_name}'
|
||||||
|
name = "${name}"
|
||||||
|
|
||||||
|
# TODO: you must declare all desired output columns for Excel
|
||||||
|
output_fields = [
|
||||||
|
'customer_number',
|
||||||
|
'customer_name',
|
||||||
|
]
|
||||||
|
|
||||||
|
def make_data(self, session, params, progress=None, **kwargs):
|
||||||
|
|
||||||
|
# TODO: obviously you must do whatever queries you need, to gather
|
||||||
|
# all data required for your report
|
||||||
|
|
||||||
|
# looking for all customers
|
||||||
|
customers = session.query(model.Customer)\
|
||||||
|
.order_by(model.Customer.number) #\
|
||||||
|
# .options(orm.joinedload(model.Customer._people)\
|
||||||
|
# .joinedload(model.CustomerPerson.person))
|
||||||
|
|
||||||
|
# returned object will be a list of dicts
|
||||||
|
rows = []
|
||||||
|
|
||||||
|
def include(customer, i):
|
||||||
|
# person = customer.only_person()
|
||||||
|
rows.append({
|
||||||
|
'customer_number': customer.number,
|
||||||
|
'customer_name': customer.name,
|
||||||
|
})
|
||||||
|
|
||||||
|
self.progress_loop(include, customers, progress,
|
||||||
|
message="Fetching data for report")
|
||||||
|
return rows
|
||||||
|
```
|
||||||
|
|
||||||
|
For more help please see the
|
||||||
|
[Rattail Manual](https://rattailproject.org/docs/rattail-manual/),
|
||||||
|
in particular these sections:
|
||||||
|
|
||||||
|
- [Reports](https://rattailproject.org/docs/rattail-manual/data/reports/index.html)
|
104
rattail/templates/feature/new-table/instructions.mako
Normal file
104
rattail/templates/feature/new-table/instructions.mako
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
## -*- mode: markdown; -*-
|
||||||
|
# New Table: ${prefixed_model_name}
|
||||||
|
|
||||||
|
Create a new Python module under `${app_package}.db.model`, for instance at
|
||||||
|
`~/src/${app_slug}/${app_package}/db/model/${table_name}.py`, with contents:
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
Table schema for ${model_title_plural}
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
# from sqlalchemy import orm
|
||||||
|
|
||||||
|
from rattail.db.model import Base, uuid_column
|
||||||
|
|
||||||
|
|
||||||
|
class ${prefixed_model_name}(Base):
|
||||||
|
"""
|
||||||
|
${description}
|
||||||
|
"""
|
||||||
|
__tablename__ = '${prefixed_table_name}'
|
||||||
|
model_title = "${model_title}"
|
||||||
|
model_title_plural = "${model_title_plural}"
|
||||||
|
% if versioned:
|
||||||
|
|
||||||
|
# this enables data versioning for the table
|
||||||
|
__versioned__ = {}
|
||||||
|
% endif
|
||||||
|
|
||||||
|
# universally-unique identifier
|
||||||
|
uuid = uuid_column()
|
||||||
|
|
||||||
|
# TODO: you must explicitly define remaining columns
|
||||||
|
|
||||||
|
# id = sa.Column(sa.Integer(), nullable=True, doc="""
|
||||||
|
# Presumably unique ID number for the record.
|
||||||
|
# """)
|
||||||
|
|
||||||
|
# TODO: we include this only as an example. your table may not need a name
|
||||||
|
# column, in which case please remove. but if so be sure to also update
|
||||||
|
# the __str__() method below.
|
||||||
|
name = sa.Column(sa.String(length=255), nullable=True, doc="""
|
||||||
|
Name of the ${model_title}.
|
||||||
|
""")
|
||||||
|
|
||||||
|
# flag = sa.Column(sa.Boolean(), nullable=True, doc="""
|
||||||
|
# Flag indicating something.
|
||||||
|
# """)
|
||||||
|
|
||||||
|
# timestamp = sa.Column(sa.DateTime(), nullable=True, doc="""
|
||||||
|
# Time and date when something happens.
|
||||||
|
# """)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name or ""
|
||||||
|
```
|
||||||
|
|
||||||
|
You should review all code in the module, and edit as needed, before
|
||||||
|
continuing.
|
||||||
|
|
||||||
|
Make sure to bring it into your root model namespace also, for instance in
|
||||||
|
`~/src/${app_slug}/${app_package}/db/model/__init__.py` add this:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from .${table_name} import ${prefixed_model_name}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then generate a new Alembic version script for the schema migration:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd ${envroot}
|
||||||
|
bin/alembic -c app/rattail.conf revision --autogenerate --head ${app_package}@head -m "add ${prefixed_table_name}"
|
||||||
|
```
|
||||||
|
|
||||||
|
That should create a new script somewhere in e.g.
|
||||||
|
`~/src/${app_slug}/${app_package}/db/alembic/versions/`.
|
||||||
|
|
||||||
|
Edit the migration script as needed, then apply it to your database:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd ${envroot}
|
||||||
|
bin/alembic -c app/rattail.conf upgrade heads
|
||||||
|
```
|
||||||
|
|
||||||
|
At this point your DB should have the new table. You can see details with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -u postgres psql -c '\d ${prefixed_table_name}' ${app_package}
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you are happy with the result, don't forget to commit!
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd ~/src/${app_slug}
|
||||||
|
git add .
|
||||||
|
git commit -m "add model for ${prefixed_model_name}"
|
||||||
|
```
|
||||||
|
|
||||||
|
For more help please see the
|
||||||
|
[Rattail Manual](https://rattailproject.org/docs/rattail-manual/),
|
||||||
|
in particular these sections:
|
||||||
|
|
||||||
|
- [Rattail Database](https://rattailproject.org/docs/rattail-manual/data/db/index.html)
|
7
setup.py
7
setup.py
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2020 Lance Edgar
|
# Copyright © 2010-2021 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -63,6 +63,7 @@ requires = [
|
||||||
# package # low high
|
# package # low high
|
||||||
|
|
||||||
'bcrypt', # 3.1.4
|
'bcrypt', # 3.1.4
|
||||||
|
'colander', # 1.8.3
|
||||||
'humanize', # 0.5.1
|
'humanize', # 0.5.1
|
||||||
'lockfile', # 0.9.1
|
'lockfile', # 0.9.1
|
||||||
'openpyxl', # 2.5.0
|
'openpyxl', # 2.5.0
|
||||||
|
@ -241,6 +242,10 @@ new-batch = rattail.commands.dev:NewBatch
|
||||||
rattail.db = rattail.db:ConfigExtension
|
rattail.db = rattail.db:ConfigExtension
|
||||||
rattail.trainwreck = rattail.trainwreck.config:TrainwreckConfig
|
rattail.trainwreck = rattail.trainwreck.config:TrainwreckConfig
|
||||||
|
|
||||||
|
[rattail.features]
|
||||||
|
new-report = rattail.features.newreport:NewReportFeature
|
||||||
|
new-table = rattail.features.newtable:NewTableFeature
|
||||||
|
|
||||||
[rattail.sil.column_providers]
|
[rattail.sil.column_providers]
|
||||||
rattail = rattail.sil.columns:provide_columns
|
rattail = rattail.sil.columns:provide_columns
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue