On 26 май, 18:24, "Michael Bayer" <mike...@zzzcomputing.com> wrote:
> Denis S. Otkidach wrote:
>
> > such ability in SQLAlchemy. There is a suggestion (
> >http://groups.google.com/group/sqlalchemy/browse_thread/thread/bcd10e...
> > ) to provide custom query_cls. This probably worked a year ago, but
> > doesn't work now.
>
> that should absolutely work now.  "doesn't work" is never a very useful
> explanation of a problem.

Sure, my report is not verbose enough. Here is a part of traceback
when my QueryPublic is used:

[... here is code equivalent to:
for link in doc.links:
    link.ref_doc.events_sections[0].slug # <- failes here
...]
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/attributes.py", line 158, in __get__
    return self.impl.get(instance_state(instance), instance_dict
(instance))
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/attributes.py", line 374, in get
    value = callable_()
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/strategies.py", line 559, in __call__
    return q.get(ident)
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/query.py", line 442, in get
    return self._get(key, ident)
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/query.py", line 1396, in _get
    q.__no_criterion_condition("get")
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/query.py", line 271, in __no_criterion_condition
    raise sa_exc.InvalidRequestError("Query.%s() being called on a
Query with existing criterion. " % meth)
InvalidRequestError: Query.get() being called on a Query with existing
criterion.

And when I redefine get() it comes a bit farther:

[... here is code equivalent to:
for link in doc.links:
    link.ref_doc.events_sections[0].slug
    link.ref_doc.short_title # <- failes here
...]
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/attributes.py", line 158, in __get__
    return self.impl.get(instance_state(instance), instance_dict
(instance))
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/attributes.py", line 374, in get
    value = callable_()
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/state.py", line 171, in __call__
    attr.impl.key in unmodified
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/mapper.py", line 1834, in _load_scalar_attributes
    result = session.query(mapper).from_statement(statement)._get
(None, only_load_props=attribute_names, refresh_state=state)
  File "<string>", line 1, in <lambda>
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/query.py", line 51, in generate
    assertion(self, fn.func_name)
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/query.py", line 281, in __no_clauseelement_condition
    self.__no_criterion_condition(meth)
  File "/home/web/third-party/SQLAlchemy-0.5.4p1-py2.5.egg/sqlalchemy/
orm/query.py", line 271, in __no_criterion_condition
    raise sa_exc.InvalidRequestError("Query.%s() being called on a
Query with existing criterion. " % meth)
InvalidRequestError: Query.from_statement() being called on a Query
with existing criterion.

Condition is:

class Doc([...base declarative model...]):
    [...]
    state = Column(Integer, nullable=False, default=0, index=True)
    [...]
    PUBLISHED = 4
    public_condition = (state==PUBLISHED)

Here doc (retrieved from session by id) and doc_ref (via 2 relations)
are instances of Doc class. Other models here don't have
public_condition yet.

> > Here is query class I pass as query_cls argument to sessionmaker:
>
> > def QueryPublic(entities, session=None):
> >     query = Query(entities, session)
> >     # XXX I haven't ever seen examples with several entities, so I can
> > test
> >     # this case.
> >     assert len(entities)==1, entities
> >     # XXX Sometimes it's not a model class or mapper, so the following
> > fails.
> >     cls = _class_to_mapper(entities[0]).class_
> >     public_condition = getattr(cls, 'public_condition', None)
> >     if public_condition is not None:
> >         query = query.filter(public_condition)
> >     return query
>
> > This works for simple queries, but any access to relation gives an
> > about Query.get() used for query with condition (this wasn't a case
> > for 0.4.x).
>
> get() should never be called when there's any filtering applied.  its a
> nonsensical operation so 0.5 likes to tell you about it.

I don't call it explicitly, but it is called internally when I access
property defined with relation().

> > OK, i've redefined get() method to be less restrictive in
> > cost of performance:
>
> > class HackedQuery(Query):
>
> >     def get(self, ident):
> >         # XXX This works for case when primary key is constructed of
> > id field
> >         # only.
> >         if isinstance(ident, (tuple, list)):
> >             assert len(ident)==1
> >             ident = ident[0]
> >         return self.filter_by(id=ident).first()
>
> > This helped for some properties access, but not all. Right now I have
> > a similar error for statement_from() method. Probably I can fix this
> > too, but how many methods I have to overwrite to make it working
> > ever?
>
> its not clear here if you want filtering to be applied when lazyloaders
> fire off or not.   Also, get() is really a special method- you've
> completely broken it above, such that it won't first check the session for
> the desired object (a major performance element), it wont check the
> expired status, etc.

Performance is certainly less important than avoiding a lot of errors
due to forgotten manually applied filters, so it's OK for us. And I
don't understand the problem with expired status, in fact it'd prefer
to forbid reloading of objects at all in public part of project.

> I'm a little mystified what such a criterion could be that would work
> across all your tables.   I don't understand what's wrong with using
> relation() to define the appropriate primaryjoin is.  If you don't want to
> "type" it over and over again, just make your own relation() function that
> applies the desired primaryjoin in an automated fashion and then returns
> the result of SQLAlchemy's relation().

Do you mean I have to create separate model definitions for public and
private parts of site? It doesn't seem sane to me. I've used such
filtering across all tables for over 10 years with other DB tools, and
it saved me a lot of work. Why not using it with SA?
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to