diff --git a/.gitignore b/.gitignore index 0df43ff..e02d796 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ nosetests.xml # Virtualenv folders local include -test-project/testproject/test-project.sqlite +*.sqlite diff --git a/README.md b/README.md index 4bcbdb9..9502f93 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ sqlalchemy-datatables [![Build Status](https://travis-ci.org/Pegase745/sqlalchem ===================== ## Usage -The package is available on [PyPI] (https://pypi.python.org/pypi/sqlalchemy-datatables/0.1.0) +The package is available on [PyPI] (https://pypi.python.org/pypi/sqlalchemy-datatables/0.1.2) > pip install sqlalchemy-datatables @@ -96,15 +96,30 @@ def simple_example(request): $ git clone $ virtualenv --no-site-packages sqlalchemy-datatables $ cd sqlalchemy-datatables/ -$ cd test-project/ -$ $venv/bin/python setup.py develop - Once only: -$ $venv/bin/python sqlalchemy-datatables/setup.py develop +$ bin/python setup.py develop +$ cd test-project/ +$ $venv/bin/python setup.py develop +$ $venv/bin/initialize_test-project_db development.ini $ $venv/bin/pserve development.ini + +Open a web browser and got to the url localhost:6543 ``` +## Changelog + +#### v0.1.2 (13/08/2013)#### +- Fixing errors due to relationships (filtering, sorting) +- Setting filter default value to str, avoiding JSON serializable type errors + +#### v0.1.1 (12/08/2013)#### +- Fixing viewing column relationships + +#### v0.1.0 (12/08/2013)#### +- First version + + ## License Copyright (c) 2013 Michel Nemnom diff --git a/datatables/__init__.py b/datatables/__init__.py index 196dea9..e67961e 100644 --- a/datatables/__init__.py +++ b/datatables/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- -__VERSION__ = '0.1.1' +__VERSION__ = '0.1.2' -from datatables import * \ No newline at end of file +from datatables import * diff --git a/datatables/datatables.py b/datatables/datatables.py index 81dfed3..e94da99 100644 --- a/datatables/datatables.py +++ b/datatables/datatables.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from sqlalchemy.sql.expression import asc, desc from sqlalchemy.sql import or_ +from sqlalchemy.orm.properties import RelationshipProperty from collections import namedtuple @@ -29,8 +30,10 @@ class ColumnDT(ColumnTuple): :returns: a ColumnDT object """ - def __new__(cls, column_name, mData=None, filter=None): - """On creation, sets default None values for mData and filter + def __new__(cls, column_name, mData=None, filter=str): + """ + On creation, sets default None values for mData and string value for + filter (cause: Object representation is not JSON serializable) """ return super(ColumnDT, cls).__new__(cls, column_name, mData, filter) @@ -121,7 +124,20 @@ def filtering(self): if search_value: for col in self.columns: - conditions.append(getattr(self.sqla_object, col.column_name).like("%" + search_value + "%")) + tmp_column_name = col.column_name.split('.') + obj = getattr(self.sqla_object, tmp_column_name[0]) + if isinstance(obj.property, RelationshipProperty): # Ex: ForeignKey + # Ex: address.description + sqla_obj = obj.mapper.class_ + column_name = "".join(tmp_column_name[1:]) + if not column_name: + # find first primary key + column_name = obj.property.table.primary_key.columns \ + .values()[0].name + else: + sqla_obj = self.sqla_object + column_name = col.column_name + conditions.append(get_attr(sqla_obj, column_name).like("%" + search_value + "%")) condition = or_(*conditions) self.query = self.query.filter(condition) @@ -147,7 +163,20 @@ def sorting(self): self.request_values['sSortDir_'+str(i)])) for sort in sorting: - sort_name = self.sqla_object.__tablename__ + '.' + sort.name + tmp_sort_name = sort.name.split('.') + obj = getattr(self.sqla_object, tmp_sort_name[0]) + if isinstance(obj.property, RelationshipProperty): # Ex: ForeignKey + # Ex: address.description => description => addresses.description + sort_name = "".join(tmp_sort_name[1:]) + if not sort_name: + # Find first piramry key + sort_name = obj.property.table.primary_key.columns \ + .values()[0].name + tablename = obj.property.table.name + else: #-> ColumnProperty + sort_name = sort.name + tablename = self.sqla_object.__tablename__ + sort_name = "%s.%s" % (tablename, sort_name) self.query = self.query.order_by( asc(sort_name) if sort.dir == 'asc' else desc(sort_name)) @@ -163,4 +192,4 @@ def paging(self): pages.length = int(self.request_values['iDisplayLength']) offset = pages.start + pages.length - self.query = self.query.slice(pages.start, offset) \ No newline at end of file + self.query = self.query.slice(pages.start, offset) diff --git a/test-project/testproject/models.py b/test-project/testproject/models.py index 14aec8f..16813dc 100644 --- a/test-project/testproject/models.py +++ b/test-project/testproject/models.py @@ -32,6 +32,12 @@ class User(Base): def __init__(self, name): self.name = name + def __str__(self): + return u"%s" % self.name + + def __repr__(self): + return '<%s#%s>' % (self.__class__.__name__, self.id) + class Address(Base): __tablename__ = 'addresses' @@ -42,5 +48,8 @@ class Address(Base): def __init__(self, description): self.description = description + def __str__(self): + return "%s" % (self.id) + def __repr__(self): - pass + return '<%s#%s>' % (self.__class__.__name__, self.id) diff --git a/test-project/testproject/scripts/initializedb.py b/test-project/testproject/scripts/initializedb.py index 8a786f4..bf7374b 100644 --- a/test-project/testproject/scripts/initializedb.py +++ b/test-project/testproject/scripts/initializedb.py @@ -37,9 +37,9 @@ def main(argv=sys.argv): with transaction.manager: i = 0 while i < 30: - address = Address(description='Address#' + str(i)) + address = Address(description='Address#2' + str(i).rjust(2, "0")) DBSession.add(address) - user = User(name='User#' + str(i)) + user = User(name='User#1' + str(i).rjust(2, "0")) user.address = address DBSession.add(user) sleep(1) diff --git a/test-project/testproject/views.py b/test-project/testproject/views.py index b1e387a..f2e0134 100644 --- a/test-project/testproject/views.py +++ b/test-project/testproject/views.py @@ -53,7 +53,7 @@ def simple_example(request): columns.append(ColumnDT('id')) columns.append(ColumnDT('name', None, _upper)) columns.append(ColumnDT('address.description')) - columns.append(ColumnDT('created_at', None , str)) + columns.append(ColumnDT('created_at')) # defining the initial query depending on your purpose query = DBSession.query(User).join(Address).filter(Address.id > 14) @@ -67,4 +67,4 @@ def simple_example(request): @view_config(route_name='relation_example', request_method='GET', renderer='json') def relation_example(request): - pass \ No newline at end of file + pass