diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 0bd87c3..3610b05 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -12,7 +12,7 @@ library. This means that you can simply use something like that: .. literalinclude:: ../eve_sqlalchemy/examples/simple/tables.py -We have used ``CommonColumns`` abstract class to provide attributes used by +We have used ``BaseModel`` abstract class to provide attributes used by Eve, such as ``_created`` and ``_updated``. These are not needed if you are only reading from the database. However, if your API is also writing to the database, then you need to include them. diff --git a/docs/upgrading.rst b/docs/upgrading.rst index 63f8048..7eb0585 100644 --- a/docs/upgrading.rst +++ b/docs/upgrading.rst @@ -29,7 +29,7 @@ directory): .. code-block:: python - class People(CommonColumns): + class People(BaseModel): __tablename__ = 'people' id = Column(Integer, primary_key=True, autoincrement=True) firstname = Column(String(80)) @@ -37,7 +37,7 @@ directory): fullname = column_property(firstname + " " + lastname) - class Invoices(CommonColumns): + class Invoices(BaseModel): __tablename__ = 'invoices' id = Column(Integer, primary_key=True, autoincrement=True) number = Column(Integer) diff --git a/eve_sqlalchemy/declarative.py b/eve_sqlalchemy/declarative.py new file mode 100644 index 0000000..62f3d1a --- /dev/null +++ b/eve_sqlalchemy/declarative.py @@ -0,0 +1,15 @@ +from sqlalchemy import Column, DateTime, String, func +from sqlalchemy.ext.declarative import declarative_base + + +class BaseModel(object): + """ + Master Eve model for SQLALchemy. It provides common columns such as + _created, _updated, and _etag. + """ + _created = Column(DateTime, default=func.now()) + _updated = Column(DateTime, default=func.now(), onupdate=func.now()) + _etag = Column(String(40)) + + +BaseModel = declarative_base(cls=BaseModel) diff --git a/eve_sqlalchemy/tests/__init__.py b/eve_sqlalchemy/tests/__init__.py index 3e616b3..19323b8 100644 --- a/eve_sqlalchemy/tests/__init__.py +++ b/eve_sqlalchemy/tests/__init__.py @@ -19,7 +19,7 @@ from eve import ISSUES from eve_sqlalchemy import SQL -from eve_sqlalchemy.tests.test_sql_tables import Base +from eve_sqlalchemy.declarative import BaseModel from eve_sqlalchemy.validation import ValidatorSQL @@ -47,7 +47,7 @@ def setUp(self, settings_file=None, url_converters=None, if declarative_base is not None: SQL.driver.Model = declarative_base else: - SQL.driver.Model = Base + SQL.driver.Model = BaseModel self.app = eve.Eve(settings=self.settings_file, url_converters=url_converters, data=SQL, diff --git a/eve_sqlalchemy/tests/config/__init__.py b/eve_sqlalchemy/tests/config/__init__.py index 3772b49..24a106b 100644 --- a/eve_sqlalchemy/tests/config/__init__.py +++ b/eve_sqlalchemy/tests/config/__init__.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from sqlalchemy import Column, DateTime, String, func from sqlalchemy.ext.declarative import declared_attr +from eve_sqlalchemy.declarative import BaseModel + def call_for(*args): def decorator(f): @@ -14,11 +15,8 @@ def loop(self): return decorator -class BaseModel(object): +class BaseModel(BaseModel): __abstract__ = True - _created = Column(DateTime, default=func.now()) - _updated = Column(DateTime, default=func.now()) - _etag = Column(String) @declared_attr def __tablename__(cls): diff --git a/eve_sqlalchemy/tests/integration/collection_class_set.py b/eve_sqlalchemy/tests/integration/collection_class_set.py index 0b10cd4..3f99c96 100644 --- a/eve_sqlalchemy/tests/integration/collection_class_set.py +++ b/eve_sqlalchemy/tests/integration/collection_class_set.py @@ -1,27 +1,15 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from sqlalchemy import ( - Column, DateTime, ForeignKey, Integer, String, Table, func, -) -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, ForeignKey, Integer, Table from sqlalchemy.orm import relationship from eve_sqlalchemy.config import DomainConfig, ResourceConfig +from eve_sqlalchemy.declarative import BaseModel from eve_sqlalchemy.tests import TestMinimal -Base = declarative_base() - - -class BaseModel(Base): - __abstract__ = True - _created = Column(DateTime, default=func.now()) - _updated = Column(DateTime, default=func.now(), onupdate=func.now()) - _etag = Column(String(40)) - - association_table = Table( - 'association', Base.metadata, + 'association', BaseModel.metadata, Column('left_id', Integer, ForeignKey('left.id')), Column('right_id', Integer, ForeignKey('right.id')) ) @@ -55,7 +43,7 @@ class TestCollectionClassSet(TestMinimal): def setUp(self, url_converters=None): super(TestCollectionClassSet, self).setUp( - SETTINGS, url_converters, Base) + SETTINGS, url_converters, BaseModel) def bulk_insert(self): self.app.data.insert('children', [{'id': k} for k in range(1, 5)]) diff --git a/eve_sqlalchemy/tests/integration/get_none_values.py b/eve_sqlalchemy/tests/integration/get_none_values.py index f7df07a..13ce38a 100644 --- a/eve_sqlalchemy/tests/integration/get_none_values.py +++ b/eve_sqlalchemy/tests/integration/get_none_values.py @@ -1,21 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from sqlalchemy import Column, DateTime, Integer, String, func -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer from eve_sqlalchemy.config import DomainConfig, ResourceConfig +from eve_sqlalchemy.declarative import BaseModel from eve_sqlalchemy.tests import TestMinimal -Base = declarative_base() - - -class BaseModel(Base): - __abstract__ = True - _created = Column(DateTime, default=func.now()) - _updated = Column(DateTime, default=func.now(), onupdate=func.now()) - _etag = Column(String(40)) - class Node(BaseModel): __tablename__ = 'node' @@ -37,7 +28,8 @@ class Node(BaseModel): class TestGetNoneValues(TestMinimal): def setUp(self, url_converters=None): - super(TestGetNoneValues, self).setUp(SETTINGS, url_converters, Base) + super(TestGetNoneValues, self).setUp(SETTINGS, url_converters, + BaseModel) def bulk_insert(self): self.app.data.insert('nodes', [{'id': k} for k in range(1, 5)]) diff --git a/eve_sqlalchemy/tests/test_sql_tables.py b/eve_sqlalchemy/tests/test_sql_tables.py index a515829..2b545e2 100644 --- a/eve_sqlalchemy/tests/test_sql_tables.py +++ b/eve_sqlalchemy/tests/test_sql_tables.py @@ -1,46 +1,23 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -import hashlib - from sqlalchemy import ( Boolean, Column, DateTime, Float, ForeignKey, Integer, LargeBinary, - PickleType, String, Table, func, + PickleType, String, Table, ) -from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship -Base = declarative_base() - - -class CommonColumns(Base): - """ - Master SQLAlchemy Model. All the SQL tables defined for the application - should inherit from this class. It provides common columns such as - _created, _updated and _id. - - WARNING: the _id column name does not respect Eve's setting for custom - ID_FIELD. - """ - __abstract__ = True - _created = Column(DateTime, default=func.now()) - _updated = Column(DateTime, default=func.now(), onupdate=func.now()) - _etag = Column(String) - - def __init__(self, *args, **kwargs): - h = hashlib.sha1() - self._etag = h.hexdigest() - super(CommonColumns, self).__init__(*args, **kwargs) +from eve_sqlalchemy.declarative import BaseModel -class DisabledBulk(CommonColumns): +class DisabledBulk(BaseModel): __tablename__ = 'disabled_bulk' _id = Column(Integer, primary_key=True) string_field = Column(String(25)) InvoicingContacts = Table( - 'invoicing_contacts', Base.metadata, + 'invoicing_contacts', BaseModel.metadata, Column('invoice_id', Integer, ForeignKey('invoices._id'), primary_key=True), Column('contact_id', Integer, ForeignKey('contacts._id'), @@ -48,7 +25,7 @@ class DisabledBulk(CommonColumns): ) -class Contacts(CommonColumns): +class Contacts(BaseModel): __tablename__ = 'contacts' _id = Column(Integer, primary_key=True) ref = Column(String(25), unique=True, nullable=False) @@ -81,7 +58,7 @@ class Contacts(CommonColumns): abool = Column(Boolean) -class Invoices(CommonColumns): +class Invoices(BaseModel): __tablename__ = 'invoices' _id = Column(Integer, primary_key=True) inv_number = Column(String(25)) @@ -90,14 +67,14 @@ class Invoices(CommonColumns): invoicing_contacts = relationship('Contacts', secondary=InvoicingContacts) -class Empty(CommonColumns): +class Empty(BaseModel): __tablename__ = 'empty' _id = Column(Integer, primary_key=True) inv_number = Column(String(25)) DepartmentsContacts = Table( - 'department_contacts', Base.metadata, + 'department_contacts', BaseModel.metadata, Column('department_id', Integer, ForeignKey('departments._id'), primary_key=True), Column('contact_id', Integer, ForeignKey('contacts._id'), @@ -105,7 +82,7 @@ class Empty(CommonColumns): ) CompaniesDepartments = Table( - 'companies_departments', Base.metadata, + 'companies_departments', BaseModel.metadata, Column('company_id', Integer, ForeignKey('companies._id'), primary_key=True), Column('department_id', Integer, ForeignKey('departments._id'), @@ -113,14 +90,14 @@ class Empty(CommonColumns): ) -class Departments(CommonColumns): +class Departments(BaseModel): __tablename__ = 'departments' _id = Column(Integer, primary_key=True) title = Column(String(25)) members = relationship('Contacts', secondary=DepartmentsContacts) -class Companies(CommonColumns): +class Companies(BaseModel): __tablename__ = 'companies' _id = Column(Integer, primary_key=True) holding_id = Column(String(16), ForeignKey('companies._id')) @@ -128,28 +105,28 @@ class Companies(CommonColumns): departments = relationship('Departments', secondary=CompaniesDepartments) -class Payments(CommonColumns): +class Payments(BaseModel): __tablename__ = 'payments' _id = Column(Integer, primary_key=True) a_string = Column(String(10)) a_number = Column(Integer) -class InternalTransactions(CommonColumns): +class InternalTransactions(BaseModel): __tablename__ = 'internal_transactions' _id = Column(Integer, primary_key=True) internal_string = Column(String(10)) internal_number = Column(Integer) -class Login(CommonColumns): +class Login(BaseModel): __tablename__ = 'login' _id = Column(Integer, primary_key=True) email = Column(String(255), nullable=False, unique=True) password = Column(String(32), nullable=False) -class Products(CommonColumns): +class Products(BaseModel): __tablename__ = 'products' sku = Column(String(16), primary_key=True) title = Column(String(32))