I like to keep my models separate from actions on it, so I only use them
for defining tables, relationships, and indexes. To perform actions on a
model I use a service that inherits from the model and provides . . . well.
services. It's an interface pattern. I'm making these more generic, and
separating out repeated code into a mixin. It works fine, but I kind of
hate the implementation because it feels wrong and fragile to me. I was
wondering if anyone had some suggestions to improve how I'm doing this.
Here are some examples.
class User(Base):
__tablename__ = 'users'
__table_args__ = {'sqlite_autoincrement': True}
# postgres implementation for later
# user_id_seq = Sequence('user_id_seq', metadata=Base.metadata)
# id = Column(BigInteger, user_id_seq,
server_default=user_id_seq.next_value(), primary_key=True)
id = Column(Integer, primary_key=True)
resource_uid = Column(Text, nullable=False)
username = Column(Text, nullable=False, unique=True)
hashed_password = Column(Text, nullable=True)
is_enabled = Column(Integer, default=1, nullable=False)
class CRUDMixIn:
def __init__(self):
# super().__init__()
print('initing crud mixin')
# This assumes that there are only two MixIns used in the service in
this order
# e.g.: class XService(FormMixIn, CRUDMixIn, User):
self.model = self.__class__.mro()[3]
def get_one_by_id(self, id):
one_row = self.request.dbsession.query(self.model).filter(self.model.id
== id).first()
return one
def get_all(self):
all_rows = self.request.dbsession.query(self.model).all()
return all_rows
class UserService(FormMixIn, CRUDMixIn, User):
def __init__(self, request: Request):
super().__init__()
self.request = request
# other user related methods and business logic
What is obviously really gross about this is getting the class for the
MixIn. Relying on the MRO means that anyone using it has to keep the same
order, and that feels wrong. But it doesn't feel as wrong repeating a bunch
of boilerplate CRUD code. I've looked at more than a few web/CRUD
frameworks, and I don't see people doing things like this. Most often what
I see is people putting generic CRUD functions in the Declarative Base, and
I really don't like that coupling there. I'd much prefer to have the model
layer separated from its actions. I had thought about setting the model in
the UserService like this:
class UserService(FormMixIn, CRUDMixIn, User):
def __init__(self, request: Request):
super().__init__()
self.request = request
self.model = User
But that returns a <class 'sqlalchemy.ext.declarative.api.DeclarativeMeta'>
instead of <class models.User>, so I still have to get to the MRO there to
get the user model to query and it ends up being just as ugly. Although, I
guess that's more stable than what I'm doing now because the model MRO
isn't going to change often (or ever, maybe?).
Anyway, I'm curious if anyone has thoughts about how I can make this better
or less fragile.
thanks!
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.