I ended up going with your recipe and this is my final result: class NoDeletedQuery(Query): """ Subclass query and provide a pre-fabricated WHERE clause that is applied to all queries.
It uses the enable_assertions() method available in SA v0.5.6 and above to bypass the Query object's usual checks. From: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PreFilteredQuery """ def get(self, ident): # override get() so that the flag is always checked in the # DB as opposed to pulling from the identity map. - this is optional. return Query.get(self.populate_existing(), ident) def __iter__(self): return Query.__iter__(self._criterion_filter()) def from_self(self, *ent): # override from_self() to automatically apply # the criterion too. this works with count() and # others. return Query.from_self(self._criterion_filter(), *ent) def _criterion_filter(self): # get the mapper here mzero = self._mapper_zero() # if its a mapped class and our criteria is satisfied.. if mzero is not None and 'deleted_at' in mzero.mapped_table.c: table = mzero.mapped_table not_deleted_q = select([table]).where(table.c.deleted_at == None) # need an alias to use this as a mapper because some dbs don't # support anonymous sub queries and sqlalchemy enforces. not_deleted_q = not_deleted_q.alias() return self.enable_assertions(False).select_from(not_deleted_q) else: return self Thanks for the tip! I'm now encountering another issue -- how can I ignore this query class on certain relationships? You can pass the query_class keyword argument to the relationship, but it's only for dynamic relationships. How can I change this behavior? Thanks again! On Mon, Sep 24, 2012 at 11:45 AM, Michael Bayer <mike...@zzzcomputing.com>wrote: > > On Sep 24, 2012, at 1:48 PM, Mahmoud Abdelkader wrote: > > I wanted to know some views about the soft-delete (anti?) pattern and > whether or not I'm going about it the right way in my code base. > > We have a piece of code: > > class NoDeletedQuery(Query): > def __new__(cls, *args, **kwargs): > if args and hasattr(args[0][0], "deleted_at"): > return Query(*args, **kwargs).filter_by(deleted_at=None) > else: > return object.__new__(cls) > > > Session = scoped_session(sessionmaker(query_cls=NoDeletedQuery)) > > This is pretty obvious, just auto adds a filter that ignores the deleted > at, but, I think this is a very hard thing to get right, especially with > joins and whatnot. This works, but I would like to know what's the > recommended idiom? I looked at this stack overflow question: > > > http://stackoverflow.com/questions/920724/the-right-way-to-auto-filter-sqlalchemy-queries > > > > the recipe we have in this regard is similar and is here: > > http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PreFilteredQuery > > however, it is still pretty simplistic and doesn't produce the > sub-selectable you prefer here. > > A hybrid of both approaches can be achieved with select_from(): > > class SomeQuery(Query): > def __new__(cls, *arg, **kw): > if (<we should use deleted_at>): > return Query(*arg, > **kw).select_from(select([table]).where(table.c.deleted_at==None).alias()) > else: > return object.__new__(cls) > > that is, query(cls).select_from(selectable) is roughly equivalent to > having a mapper() against "cls" that's mapped to "selectable". > > Though the ORM still uses query() internally and I'm not sure that will > get around the object deleted exception you're getting. It's also not > clear why you'd be getting that exception anyway, unless you are trying to > access an object which corresponds to a row that's marked "deleted". Only > a full stack trace and preferably a simple reproducing case would show > exactly why it's getting there. > > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To post to this group, send email to sqlalchemy@googlegroups.com. > To unsubscribe from this group, send email to > sqlalchemy+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/sqlalchemy?hl=en. > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.