On Sat, Nov 14, 2009 at 4:31 AM, Warren Smith <[email protected]> wrote: > On Thu, Nov 12, 2009 at 5:17 PM, Russell Keith-Magee > <[email protected]> wrote: >>> 1. Retrieve the credentials from the session. >>> 2. Create a new, or update an existing, entry for those credentials in >>> the database configuration. >>> 3. Somehow ensure that the using() operator is used on all ORM operations. >> >> This sounds a little more dynamic that I was anticipating. >> >> Multi-DB changes the way you define your database - instead of >> DATABASE_HOST, DATABASE_NAME etc, you have a single DATABASES >> dictionary, with each key-value pair representing a full database >> configuration, including signin credentials. > > I've looked through the code in the SVN multdb branch and Alex's > GitHub and thought about this a little more. > > I realize now that I don't need to store the credentials in session, > just the default db alias. > > The dynamic population of settings.DATABASES can happen at login time. > I can use a statically configured alias as a template, just replacing > the username and password. This new alias can be stored with a name > like '<username>@<template_alias_name>' and set in the session for use > as the default db alias in subsequent requests. > > The new multi-credential middleware would just have to take care of > getting the using() value from the session and putting it somewhere > for the ORM to use (perhaps a thread-local?). > > Is there an existing thread-local instance that would be appropriate > for storing this value?
I'm not sure this will work as you expect. Django can be served in multi-process environments, and on multiple-server environments. As a result, there is no such thing as an in-process or in-thread store that is shared between all serving instances of a Django application. If you want to share data between requests, you need to use a resource that is persistent across requests that might be served on completely different machines - like a cookie, or the database itself. As a mental model, you need to assume that each individual request will be served by a system process that will be created for that request, and destroyed as soon as the request is completed. Of course, this isn't how Django apps will be served in practice, but it accurately reflects the constraints that you need to adhere to in the general case. >> The process of actually >> opening a connection is handled by a ConnectionHandler class in >> django.db.utils. >> >> Although we haven't provided any way to override this, I suppose it >> could be replaced by an alternate implementation that creates >> connections based on credentials obtained from a session or something >> similar. I haven't given this much thought though. >> > > Though django.db.utils.ConnectionHandler is the broker of all database > connections, I'm concerned that overriding connection selection here > would overrule explicit alias declaration such as Model.Meta.using, > Model.save(using=), etc. Though it would work in my case (I'm not > using those features), it feels heavy-handed. However, since the > multi-credential use case adds an extra dimension to an already > complex problem, perhaps it does make sense for it to be mutually > exclusive with the other multi-db enabled use cases. > > What I originally envisioned was injecting the check of the request > specific default into the connection selection logic just ahead of > DEFAULT_DB_ALIAS. Unfortunately, the connection selection logic > exists in several places in the code and is not all the same (for > reasons I haven't taken the time to fully understand). > > To avoid changing any of the existing connection-selection code, I > suppose I could change DEFAULT_DB_ALIAS to a custom string subclass > that was smart enough to check for the request-specific value when > asked for his own value, but that seems like an overly complex and > counter-intuitive solution to a relatively simple logic problem. > > Would it make sense to factor out the connection selection logic into > a utility function with parameters that make it usable in all > contexts, thus yielding a single place to inject the check for the > request-specific default db alias (and perhaps other logic to support > master/slave, etc.)? That's the eventual intent - a callback or plugin that will be registered, probably with a model manager, that will provide an answer to the "which database should I be using for this query" question. Different implementations of this API will then exist for master/slave, sharding, etc. The exact form of this API is yet to be determined. I mentioned ConnectionHandler because you were talking about creating new database connections at runtime based on the user's credentials, and at some level, this will still need to happen. Tweaking ConnectionHandler is the alternative to trying to dynamically rewrite settings.DATABASE, not a solution to the 'find which connection to use' problem. Yours, Russ Magee %-) -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/django-developers?hl=.
