Trimming unused portions of the response to make it readable (which I
should have done the first time around, too)...

On Fri, 2009-03-20 at 23:41 -0400, Alex Gaynor wrote:
> 
> 
> On Fri, Mar 20, 2009 at 11:21 PM, Malcolm Tredinnick
> <malc...@pointy-stick.com> wrote:
>         
>         
>         On Fri, 2009-03-20 at 09:45 -0400, Alex Gaynor wrote:
>         > Hello all,

[...]

>         > The greatest hurdle is changing the connection after we
>         already have
>         > our
>         > ``Query`` partly created.  The issues here are that: we
>         might have
>         > done tests
>         > against ``connection.features`` already, we might need to
>         switch
>         > either to or
>         > from a custom ``Query`` object, amongst other issues.

[...]

>         >  One possible solution
>         > that is very powerful(though quite inellegant) is to have
>         the
>         > ``QuerySet`` keep
>         > track of all public API method calls against it and what
>         parameters
>         > they took,
>         > then when the ``connection`` is changed it will recreate the
>         ``Query``
>         > object
>         > by creating a "blank" one with the new connection and
>         reapplying all
>         > the
>         > methods it has stored.  This is basically a simple
>         implementation of
>         > the
>         > command pattern.
>         
>         
>         
>         
>         It's pretty yukky. There's a lot of Python level junk that we
>         intentionally avoid storing in querysets so that they behave
>         properly as
>         persistent data structures (clones are independent copies) and
>         can be
>         pickled without trouble, etc. It would be really bad for
>         performance to
>         reintroduce those (I did a lot of profiling when developing
>         that stuff
>         and tried to throw out as much as possible). I think this
>         fortunately
>         isn't going to be a real issue. I was pretty careful
>         originally to keep
>         the leakage from django.db.connection into the Query class to
>         as few
>         places as possible and mostly when we're creating the SQL.
>         
>         Some cases that might eb unavoidable could be replaced with
>         delayed
>         evaluation objects (essentially encapsulating the command
>         pattern just
>         for that fragment), which is a bit cleaner.
>         
> 
> One suggestion Eric Florenzano had was that we go above and beyond
> just storing the methods and parameters, we don't even excecute them
> at all until absolutely necessary.  

Excuse me for a moment whilst I add Eric to a special list I've been
keeping. He's trying to make trouble.

Ok, back now... There are at least two problems with this.

(a) Backwards incompatible in that some querysets would return
noticeably different results before and after that change. It would be
subtle, quiet and very difficult to detect without auditing every line
of code that contributes to a queryset. The worst kind of change for us
to make from the perspective of the users.

(b) Intentionally not done right now and not because I'm whimsical and
arbitrary (although I am). The problem is it requires storing all sorts
of arbitrarily complex Python objects. Which breaks pickling, which
breaks caching. People tend to complain, a lot, about that last bit.

That's why the Where.add() converts things to more basic types when they
are added (via a filter() command).  If somebody really needs lazily
evaluated parameters, it's easy enough via a custom Q-like object, but
so far nobody has asked for that if they've gotten stuck doing it. It's
even something we could consider adding to Django, although it's not a
no-brainer given the potential to break caching.

[...]
> 
> Thanks for all the review Malcolm.

No problems.

> One question that I didn't really ask in the initial post is what
> parameters should a "DatabaseManager" receieve on it's methods, one
> suggestion is the Query object, since that gives the use the maximal
> amount of information,, however my concerns there are that it's not a
> public API, and having a private API as a part of the public API feels
> klunky.

At first glance, I believe the word you're looking for is "wrong". :-)

Definitely a valid concern.

>   OTOH there isn't really another data structure that carries around
> the information someone writing their sharding logic(or whatever other
> scheme they want to implement) who inevitably want to have.

Two solutions spring to mind, although I haven't thought this through a
lot: it's not particularly germane to the proposal since it's something
we can work out a bit later on. I've got limited time today(something
about a beta release coming up), so I wanted to just get out responses
to the two people who posted items for discussion. I suspect there's a
lot of thinking needed here about the concept as a whole and I want to
do that. Anyway...

One option is to use the piece of public API that is available which
will always be carrying around a Query object: the QuerySet. Query
objects don't exist in isolation. However, this sounds problematic
because the implementation is going to be working at a very low-level --
database managers are only really interesting to Query.as_sql() and it's
dependencies. But that leads to the next idea, ...

The other is to work out a better place for this database manager in the
hierarchy. It might be something that lives as an attribute on a
QuerySet. Something like the user provides a function that picks the
database based "some information" that is available to it and the base
method selects the right database to use. Since it lives in the QuerySet
namespace, it can happily access the "query" attribute there without any
encapsulation violations. The database manager then becomes two pieces,
an algorithm on QuerySet (that might just dispatch to the real algorithm
on Query), plus some user-supplied code to make the right selections.
That latter thing could be a callable object if you need the full class
structure. But the stuff QuerySet/Query needs to know about is probably
a much smaller interface than *requiring* a full class. (Did any of that
make sense?)

I think this -- the database manager concept -- is the part of your
proposal that is most up in the air with respect to what the API looks
like. Which is fine. The fact that it's something to consider is good
enough to know. Certainly put some thought into the problem, but don't
sweat the details too much just yet (in the application period). This is
one of those hard areas where you probably do need to think about it so
much it costs you sleep, you forget to eat and so on.

Regards,
Malcolm


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to