Yeah, I'm kind of rethinking my approach here. Appreciate the thoughts. On Saturday, March 23, 2019 at 1:55:34 PM UTC-5, Mike Bayer wrote: > > Just FTR i was thinking about this Q today and I usually would opt to > make a Service object stateless, and things like "request" and User > would be passed into individual methods explicitly. I usually start > application with a pattern that might be more verbose to start with, > but once you write half a dozen cases front to back, the most > appropriate pattern usually makes itself apparent and you then > refactor. > > e.g. don't overplan ahead, do it stupidly simple then expect to > refactor a few times. but also don't create state where it isnt > needed, if that makes sense. > > > On Sat, Mar 23, 2019 at 11:24 AM Andrew Martin <[email protected] > <javascript:>> wrote: > > > > 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] <javascript:>. > > To post to this group, send email to [email protected] > <javascript:>. > > Visit this group at https://groups.google.com/group/sqlalchemy. > > For more options, visit https://groups.google.com/d/optout. >
-- 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.
