Skip to content

Commit 050726c

Browse files
committed
Add an Eve-aware base class (WIP)
The idea is to provide a base class from which user Tables can inherit. Unless they are meant for read-only acces, tables will have to provide these fields anyway. Not sure on a few things: - namespace should be different? Maybe have the base-class reside in the main eve_sqlalchemy namespace, or something different than 'declarative' to avoid confusion with sqlalchemy itself (I actually followed that lead). - base class name. Maybe CommonColumns, or EveBaseModel, or something else would be more appropriate? - What if the user changes ETAG, CREATED, UPDATED settings in the main Eve app? Again, I am not confident enough with the extension code, so careful review would be appreciated.
1 parent 916628e commit 050726c

File tree

8 files changed

+43
-75
lines changed

8 files changed

+43
-75
lines changed

docs/tutorial.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ library. This means that you can simply use something like that:
1212

1313
.. literalinclude:: ../eve_sqlalchemy/examples/simple/tables.py
1414

15-
We have used ``CommonColumns`` abstract class to provide attributes used by
15+
We have used ``BaseModel`` abstract class to provide attributes used by
1616
Eve, such as ``_created`` and ``_updated``. These are not needed if you are only
1717
reading from the database. However, if your API is also writing to the database,
1818
then you need to include them.

docs/upgrading.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ directory):
2929

3030
.. code-block:: python
3131
32-
class People(CommonColumns):
32+
class People(BaseModel):
3333
__tablename__ = 'people'
3434
id = Column(Integer, primary_key=True, autoincrement=True)
3535
firstname = Column(String(80))
3636
lastname = Column(String(120))
3737
fullname = column_property(firstname + " " + lastname)
3838
3939
40-
class Invoices(CommonColumns):
40+
class Invoices(BaseModel):
4141
__tablename__ = 'invoices'
4242
id = Column(Integer, primary_key=True, autoincrement=True)
4343
number = Column(Integer)

eve_sqlalchemy/declarative.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from sqlalchemy import Column, DateTime, String, func
2+
from sqlalchemy.ext.declarative import declarative_base
3+
4+
5+
class BaseModel(object):
6+
"""
7+
Master Eve model for SQLALchemy. It provides common columns such as
8+
_created, _updated, and _etag.
9+
"""
10+
_created = Column(DateTime, default=func.now())
11+
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
12+
_etag = Column(String(40))
13+
14+
15+
BaseModel = declarative_base(cls=BaseModel)

eve_sqlalchemy/tests/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from eve import ISSUES
2020

2121
from eve_sqlalchemy import SQL
22-
from eve_sqlalchemy.tests.test_sql_tables import Base
22+
from eve_sqlalchemy.declarative import BaseModel
2323
from eve_sqlalchemy.validation import ValidatorSQL
2424

2525

@@ -47,7 +47,7 @@ def setUp(self, settings_file=None, url_converters=None,
4747
if declarative_base is not None:
4848
SQL.driver.Model = declarative_base
4949
else:
50-
SQL.driver.Model = Base
50+
SQL.driver.Model = BaseModel
5151

5252
self.app = eve.Eve(settings=self.settings_file,
5353
url_converters=url_converters, data=SQL,

eve_sqlalchemy/tests/config/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from sqlalchemy import Column, DateTime, String, func
55
from sqlalchemy.ext.declarative import declared_attr
6+
from eve_sqlalchemy.declarative import BaseModel
67

78

89
def call_for(*args):
@@ -14,11 +15,8 @@ def loop(self):
1415
return decorator
1516

1617

17-
class BaseModel(object):
18+
class BaseModel(BaseModel):
1819
__abstract__ = True
19-
_created = Column(DateTime, default=func.now())
20-
_updated = Column(DateTime, default=func.now())
21-
_etag = Column(String)
2220

2321
@declared_attr
2422
def __tablename__(cls):

eve_sqlalchemy/tests/integration/collection_class_set.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import unicode_literals
33

4-
from sqlalchemy import (
5-
Column, DateTime, ForeignKey, Integer, String, Table, func,
6-
)
7-
from sqlalchemy.ext.declarative import declarative_base
4+
from sqlalchemy import Column, ForeignKey, Integer, Table
85
from sqlalchemy.orm import relationship
96

107
from eve_sqlalchemy.config import DomainConfig, ResourceConfig
8+
from eve_sqlalchemy.declarative import BaseModel
119
from eve_sqlalchemy.tests import TestMinimal
1210

13-
Base = declarative_base()
14-
15-
16-
class BaseModel(Base):
17-
__abstract__ = True
18-
_created = Column(DateTime, default=func.now())
19-
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
20-
_etag = Column(String(40))
21-
2211

2312
association_table = Table(
24-
'association', Base.metadata,
13+
'association', BaseModel.metadata,
2514
Column('left_id', Integer, ForeignKey('left.id')),
2615
Column('right_id', Integer, ForeignKey('right.id'))
2716
)
@@ -55,7 +44,7 @@ class TestCollectionClassSet(TestMinimal):
5544

5645
def setUp(self, url_converters=None):
5746
super(TestCollectionClassSet, self).setUp(
58-
SETTINGS, url_converters, Base)
47+
SETTINGS, url_converters, BaseModel)
5948

6049
def bulk_insert(self):
6150
self.app.data.insert('children', [{'id': k} for k in range(1, 5)])

eve_sqlalchemy/tests/integration/get_none_values.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,11 @@
22
from __future__ import unicode_literals
33

44
from sqlalchemy import Column, DateTime, Integer, String, func
5-
from sqlalchemy.ext.declarative import declarative_base
65

76
from eve_sqlalchemy.config import DomainConfig, ResourceConfig
87
from eve_sqlalchemy.tests import TestMinimal
98

10-
Base = declarative_base()
11-
12-
13-
class BaseModel(Base):
14-
__abstract__ = True
15-
_created = Column(DateTime, default=func.now())
16-
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
17-
_etag = Column(String(40))
9+
from eve_sqlalchemy.declarative import BaseModel
1810

1911

2012
class Node(BaseModel):
@@ -37,7 +29,7 @@ class Node(BaseModel):
3729
class TestGetNoneValues(TestMinimal):
3830

3931
def setUp(self, url_converters=None):
40-
super(TestGetNoneValues, self).setUp(SETTINGS, url_converters, Base)
32+
super(TestGetNoneValues, self).setUp(SETTINGS, url_converters, BaseModel)
4133

4234
def bulk_insert(self):
4335
self.app.data.insert('nodes', [{'id': k} for k in range(1, 5)])

eve_sqlalchemy/tests/test_sql_tables.py

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,28 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import unicode_literals
33

4-
import hashlib
5-
6-
from sqlalchemy import (
7-
Boolean, Column, DateTime, Float, ForeignKey, Integer, LargeBinary,
8-
PickleType, String, Table, func,
9-
)
10-
from sqlalchemy.ext.declarative import declarative_base
4+
from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Integer, LargeBinary, PickleType, String, Table
115
from sqlalchemy.orm import relationship
126

13-
Base = declarative_base()
14-
15-
16-
class CommonColumns(Base):
17-
"""
18-
Master SQLAlchemy Model. All the SQL tables defined for the application
19-
should inherit from this class. It provides common columns such as
20-
_created, _updated and _id.
21-
22-
WARNING: the _id column name does not respect Eve's setting for custom
23-
ID_FIELD.
24-
"""
25-
__abstract__ = True
26-
_created = Column(DateTime, default=func.now())
27-
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
28-
_etag = Column(String)
29-
30-
def __init__(self, *args, **kwargs):
31-
h = hashlib.sha1()
32-
self._etag = h.hexdigest()
33-
super(CommonColumns, self).__init__(*args, **kwargs)
7+
from eve_sqlalchemy.declarative import BaseModel
348

359

36-
class DisabledBulk(CommonColumns):
10+
class DisabledBulk(BaseModel):
3711
__tablename__ = 'disabled_bulk'
3812
_id = Column(Integer, primary_key=True)
3913
string_field = Column(String(25))
4014

4115

4216
InvoicingContacts = Table(
43-
'invoicing_contacts', Base.metadata,
17+
'invoicing_contacts', BaseModel.metadata,
4418
Column('invoice_id', Integer, ForeignKey('invoices._id'),
4519
primary_key=True),
4620
Column('contact_id', Integer, ForeignKey('contacts._id'),
4721
primary_key=True)
4822
)
4923

5024

51-
class Contacts(CommonColumns):
25+
class Contacts(BaseModel):
5226
__tablename__ = 'contacts'
5327
_id = Column(Integer, primary_key=True)
5428
ref = Column(String(25), unique=True, nullable=False)
@@ -81,7 +55,7 @@ class Contacts(CommonColumns):
8155
abool = Column(Boolean)
8256

8357

84-
class Invoices(CommonColumns):
58+
class Invoices(BaseModel):
8559
__tablename__ = 'invoices'
8660
_id = Column(Integer, primary_key=True)
8761
inv_number = Column(String(25))
@@ -90,66 +64,66 @@ class Invoices(CommonColumns):
9064
invoicing_contacts = relationship('Contacts', secondary=InvoicingContacts)
9165

9266

93-
class Empty(CommonColumns):
67+
class Empty(BaseModel):
9468
__tablename__ = 'empty'
9569
_id = Column(Integer, primary_key=True)
9670
inv_number = Column(String(25))
9771

9872

9973
DepartmentsContacts = Table(
100-
'department_contacts', Base.metadata,
74+
'department_contacts', BaseModel.metadata,
10175
Column('department_id', Integer, ForeignKey('departments._id'),
10276
primary_key=True),
10377
Column('contact_id', Integer, ForeignKey('contacts._id'),
10478
primary_key=True)
10579
)
10680

10781
CompaniesDepartments = Table(
108-
'companies_departments', Base.metadata,
82+
'companies_departments', BaseModel.metadata,
10983
Column('company_id', Integer, ForeignKey('companies._id'),
11084
primary_key=True),
11185
Column('department_id', Integer, ForeignKey('departments._id'),
11286
primary_key=True)
11387
)
11488

11589

116-
class Departments(CommonColumns):
90+
class Departments(BaseModel):
11791
__tablename__ = 'departments'
11892
_id = Column(Integer, primary_key=True)
11993
title = Column(String(25))
12094
members = relationship('Contacts', secondary=DepartmentsContacts)
12195

12296

123-
class Companies(CommonColumns):
97+
class Companies(BaseModel):
12498
__tablename__ = 'companies'
12599
_id = Column(Integer, primary_key=True)
126100
holding_id = Column(String(16), ForeignKey('companies._id'))
127101
holding = relationship('Companies', remote_side=[_id])
128102
departments = relationship('Departments', secondary=CompaniesDepartments)
129103

130104

131-
class Payments(CommonColumns):
105+
class Payments(BaseModel):
132106
__tablename__ = 'payments'
133107
_id = Column(Integer, primary_key=True)
134108
a_string = Column(String(10))
135109
a_number = Column(Integer)
136110

137111

138-
class InternalTransactions(CommonColumns):
112+
class InternalTransactions(BaseModel):
139113
__tablename__ = 'internal_transactions'
140114
_id = Column(Integer, primary_key=True)
141115
internal_string = Column(String(10))
142116
internal_number = Column(Integer)
143117

144118

145-
class Login(CommonColumns):
119+
class Login(BaseModel):
146120
__tablename__ = 'login'
147121
_id = Column(Integer, primary_key=True)
148122
email = Column(String(255), nullable=False, unique=True)
149123
password = Column(String(32), nullable=False)
150124

151125

152-
class Products(CommonColumns):
126+
class Products(BaseModel):
153127
__tablename__ = 'products'
154128
sku = Column(String(16), primary_key=True)
155129
title = Column(String(32))

0 commit comments

Comments
 (0)