I just realized that almost everything about how I'm using mixins here is
pretty much wrong. This is probably a garbage question and can be deleted,
but I don't want to do it myself in case someone is writing a response to
tell me that.
On Saturday, March 23, 2019 at 9:00:49 AM UTC-5, Andrew Martin wrote:
>
> 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.