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 <agmar...@gmail.com> 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 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.

-- 
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.

Reply via email to