Started using 'sqlservice'. Added support for many new tables.
This commit is contained in:
parent
9b7d7db996
commit
b77a7069ce
12 changed files with 390 additions and 125 deletions
|
|
@ -1,11 +1,12 @@
|
|||
"""
|
||||
Define an Abstract Base Class (ABC) for models
|
||||
"""
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from sqlalchemy import inspect
|
||||
|
||||
from sqlalchemy.sql.expression import and_
|
||||
from sqlalchemy.orm.collections import InstrumentedList
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
|
||||
from sqlservice import ModelBase
|
||||
|
||||
from pyjeeves import logging
|
||||
|
||||
|
|
@ -14,19 +15,25 @@ from . import db
|
|||
logger = logging.getLogger("PyJeeves." + __name__)
|
||||
|
||||
|
||||
class RawBaseModel():
|
||||
class RawBaseModel(ModelBase):
|
||||
""" Generalize __init__, __repr__ and to_json
|
||||
Based on the models columns , ForetagKod=1"""
|
||||
|
||||
print_only = () # First filter
|
||||
print_filter = () # Second filter
|
||||
to_json_filter = () # Only json filter
|
||||
column_map = {}
|
||||
__to_dict_filter__ = []
|
||||
__to_dict_only__ = ()
|
||||
__column_map__ = {}
|
||||
|
||||
__table_args__ = {
|
||||
'extend_existing': True
|
||||
}
|
||||
|
||||
__dict_args__ = {
|
||||
'adapters': {
|
||||
# datetime: lambda value, col, *_: value.strftime('%Y-%m-%d'),
|
||||
Decimal: lambda value, col, *_: "{:.2f}".format(value)
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _base_filters(self, obj, filters=and_()):
|
||||
# This method provides base filtering, additional filtering can be done in subclasses
|
||||
|
|
@ -38,63 +45,51 @@ class RawBaseModel():
|
|||
filters
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
""" Define a base way to print models
|
||||
Columns inside `print_filter` are excluded """
|
||||
return '%s(%s)' % (self.__class__.__name__, {
|
||||
column: value
|
||||
for column, value in self._to_dict().items()
|
||||
if column not in self.print_filter
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def _to_json_types(value):
|
||||
if isinstance(value, datetime):
|
||||
return value.strftime('%Y-%m-%d')
|
||||
if isinstance(value, Decimal):
|
||||
return "%.2f" % value
|
||||
try:
|
||||
if isinstance(value, InstrumentedList):
|
||||
return [x.json for x in value]
|
||||
if type(value).__module__ != 'builtins': # Perhaps == builtin?
|
||||
return value.json
|
||||
except AttributeError:
|
||||
logger.debug(str(type(value)) + " was not converted to jsonifyable type")
|
||||
return None
|
||||
|
||||
return value
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
""" Define a base way to jsonify models
|
||||
Columns inside `to_json_filter` are excluded
|
||||
Columns inside `to_json_only_filter` are only included """
|
||||
return {
|
||||
column: RawBaseModel._to_json_types(value)
|
||||
# if not isinstance(value, datetime) else value.strftime('%Y-%m-%d')
|
||||
# if type(value).__module__ != self.__module__ # Perhaps == builtin?
|
||||
# else value.json # Convert instances to json if same module
|
||||
for column, value in self._to_dict().items()
|
||||
if column not in self.to_json_filter
|
||||
}
|
||||
|
||||
def _to_dict(self):
|
||||
""" This would more or less be the same as a `to_json`
|
||||
But putting it in a "private" function
|
||||
Allows to_json to be overriden without impacting __repr__
|
||||
Or the other way around
|
||||
And to add filter lists """
|
||||
return {
|
||||
self._map_columns(column.key): getattr(self, column.key)
|
||||
for column in inspect(self.__class__).attrs
|
||||
if not self.print_only or column.key in self.print_only
|
||||
}
|
||||
|
||||
def _map_columns(self, key):
|
||||
if key in self.column_map:
|
||||
return self.column_map[key]
|
||||
if key in self.__column_map__:
|
||||
return self.__column_map__[key]
|
||||
return key
|
||||
|
||||
def descriptors_to_dict(self):
|
||||
"""Return a ``dict`` that maps data loaded in :attr:`__dict__` to this
|
||||
model's descriptors. The data contained in :attr:`__dict__` represents
|
||||
the model's state that has been loaded from the database. Accessing
|
||||
values in :attr:`__dict__` will prevent SQLAlchemy from issuing
|
||||
database queries for any ORM data that hasn't been loaded from the
|
||||
database already.
|
||||
|
||||
Note:
|
||||
The ``dict`` returned will contain model instances for any
|
||||
relationship data that is loaded. To get a ``dict`` containing all
|
||||
non-ORM objects, use :meth:`to_dict`.
|
||||
|
||||
Returns:
|
||||
dict
|
||||
"""
|
||||
descriptors = self.descriptors()
|
||||
|
||||
return { # Expose hybrid_property extension
|
||||
**{key: getattr(self, key) for key in descriptors.keys()
|
||||
if isinstance(descriptors.get(key), hybrid_property)},
|
||||
# and return all items included in descriptors
|
||||
**{key: value for key, value in self.__dict__.items()
|
||||
if key in descriptors}}
|
||||
|
||||
def to_dict(self):
|
||||
rv = super().to_dict()
|
||||
|
||||
if self.__to_dict_only__:
|
||||
return {
|
||||
self._map_columns(key): rv[key]
|
||||
for key in rv
|
||||
if key in self.__to_dict_only__
|
||||
}
|
||||
|
||||
for _filter in self.__to_dict_filter__:
|
||||
rv.pop(_filter)
|
||||
|
||||
return rv
|
||||
|
||||
def merge(self):
|
||||
db.raw_session.merge(self)
|
||||
return self
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue