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 sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.