SlideShare uma empresa Scribd logo
1 de 48
Baixar para ler offline
MultiDB In Anger
Professional Driver. Closed Course.
Hi.

Sean
OConnor in
background,
with superior
monitor.                             “Checkpoint
                                       Charlie” T-
                                            Shirt



                World Headquarters
Django MultiDB
 As It Was Probably Intended
The Legacy DB
   Problem
                             Legacy DB
   New DB,
                            that you are
  built for New
                              Unable to
   Web App
                            Eliminate. :(



                  Django
                  Website
Django ORM, Before.
        ORM API


        Database
        Backend

         Python
        Database
         Driver



        RDBMS
MultiDB Mode
            ORM API



            DB Routing


  DB          DB           DB
Definition   Definition    Definition


Database    Database     Database
Backend     Backend      Backend

 Python      Python       Python
Database    Database     Database
 Driver      Driver       Driver



RDBMS        RDBMS       RDBMS
Out of the Box

• Database definitions.
• --database=
• Database Routers.
• using(), using=
DB Definitions
settings.py
DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE':
'django.db.backends.postgresql_psycopg2',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE':
'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}
--database=

./manage.py syncdb

./manage.py syncdb --database=legacy

./manage.py migrate

./manage.py migrate --database=legacy
Database Routers
class MyAppRouter(object):
    """A router to control all database operations on models in
    the myapp application"""

    def db_for_read(self, model, **hints):
        "Point all operations on myapp models to 'other'"
        if model._meta.app_label == 'myapp':
            return 'other'
        return None

    def db_for_write(self, model, **hints):
        "Point all operations on myapp models to 'other'"
        if model._meta.app_label == 'myapp':
            return 'other'
        return None
Database Routers

settings.py
DATABASE_ROUTERS = [‘path.to.MyAppRouter’,‘path.to.OtherRouter’]
API: “using”

Author.objects.using(‘other’).all()


      p = Person(name=‘Fred’)
        p.save(using=‘db0’)
        p.save(using=‘db1’)
And now, the real
    world...
  MultiDB Meets
The Multi-Tenant Hydra

• SaaS
• Multiple accounts on a cluster.
• Each account with “substantial” data.
• Need to think about sharding.
OMG It’s Full of Stars
                    Account
                      DB
          Account             Account
            DB                  DB




     Account        Core           Account
       DB                            DB
                     DB


          Account             Account
            DB                  DB
                    Account
                      DB
Core vs. Account
•   Core DB          •   Account DBs

•   Account Data     •   Everything Else

•   User Data

•   Immutable Data
More Requirements
• Easy, declarative specification of core vs
  account for any model.
• No explicit DB references in code.
• Must route account models to correct
  account db.
• Must support web and Celery task usage.
...and even worse:


• No a priori knowledge of account
  databases. Seriously.




                                     Oh, boy...
The Hack Solution
Declarative Model Routing
class ApplicationSeat(models.Model):
    """
    A seat for an application.
    """
    app = models.ForeignKey(Application)
    user = models.ForeignKey
(UserProfile,related_name='application_seats')

    global_model = True

    def __unicode__(self):
        return '%s - %s' % (unicode(self.app),unicode(self.user))

    class Meta:
        unique_together = (('app','user'),)
Declarative Model Routing

class AccountRouter(object):
    """
    Routes models to account database, unless they are flagged
global.
    """
    def _is_saaspire(self,model):

        return model.__module__.startswith('saaspire')

    def _global(self,model):

        return hasattr(model,'global_model') and model.global_model
Routing to Core
class AccountRouter(object):
    # ...
    def db_for_read(self,model,**hints):
        """
        Gets the db for read.
        """
        from saaspire.accounts.utils import current_account
        if self._is_saaspire(model):
            if self._global(model):
                return 'default'
            else:
                self._init_dbs()
                ca = current_account()
                if ca:
                    return ca.slug
                else:
                    return None
        else:
            return None
Routing to Account
class AccountRouter(object):
    # ...
    def db_for_read(self,model,**hints):
        """
        Gets the db for read.
        """
        from saaspire.accounts.utils import current_account
        if self._is_saaspire(model):
            if self._global(model):
                return 'default'
            else:
                self._init_dbs()
                ca = current_account()
                if ca:
                    return ca.slug
                else:
                    return None
        else:
            return None
What account am I
                 using?
def current_account():
    """
    Gets the current account.
    """
    from environment import env
    # Look for explicit account specification
    if hasattr(env,'account') and env.account:
        return env.account

    # ...

    # Look for current user
    if hasattr(env,'user') and not env.user.is_anonymous():
        profile = env.user.get_profile()
        if profile:
            return profile.account

    return None
Warning:
The following scene contains threadlocals.
Django-Environment
        Start

                       Values
                   associated with
    HTTP Request
                     threadlocal
                        "env"



      Django-           View
    Environment       executes




    Environment    Threadlocal is
    Generators        cleared.




                        Stop
What account am I using?
main.env
from environment.standard import RequestAttributeGenerator
from saaspire.core.envgen import AccountGenerator, InstanceGenerator

entries = {
    'user':RequestAttributeGenerator('user'),
    'account':AccountGenerator(),
    'instance':InstanceGenerator(),
}
What account am I using?
class AccountGenerator(object):
    """
    Populates the environment with the current account.
    """
    def generate(self,key,request):
        """
        Generates the variable.
        """
        if not request.user.is_anonymous():
            return request.user.get_profile().account
        else:
            return None
What account am I using?

def current_account():
    """
    Gets the current account.
    """
    from environment import env
    # Look for explicit account specification
    if hasattr(env,'account') and env.account:
        return env.account
But what about Celery?

• Celery: An async message queue.
• No HTTP request/response cycle.
• Django-environment won’t work.
use_account() context manager



   @periodic_task(run_every=timedelta(minutes=60))
   def run_proactive_service_subinferences():

       for account in Account.objects.active():
           with use_account(account.name):
               # etc...
use_account() context manager
class use_account(object):
    """
    Context manager that sets a specific account.
    """
    def __init__(self,account_name):
        from saaspire.accounts.models import Account
        self.account = Account.objects.get(Q(name=account_name) | Q
(slug=account_name))
        self.current_account = None

    def __enter__(self):
        """
        Called at beginning of with block.
        """
        from environment import env
        if hasattr(env,'account'):
            self.current_account = env.account
        env.account = self.account

    def __exit__(self,*args,**kwargs):
        """
        Called at end of with block.
        """
        from environment import env
        env.account = self.current_account
No a priori knowledge of account databases.
This is cached in memory.
   DATABASES = {
       'default': {
           'NAME': 'app_data',
           'ENGINE':
   'django.db.backends.postgresql_psycopg2',
           'USER': 'postgres_user',
           'PASSWORD': 's3krit'
       },
       'users': {
           'NAME': 'user_data',
           'ENGINE':
   'django.db.backends.mysql',
           'USER': 'mysql_user',
           'PASSWORD': 'priv4te'
       }
   }
What we need.
  There is no     Database "X" is
 database "X".     automatically
                     created.




  Someone
                 Account "X" traffic
 signs up for
                   automatically
   Saaspire
                 routed to DB "X".
 account "X".
DBMap

settings.py
from saaspire.core.db import DBMap

DATABASES = DBMap()   # Dictionary-like thingie
{% rant %}
The way DATABASES works.

          MultiDB-aware code
          looks for a dictionary
              assigned to
          DATABASES setting.



          MultiDB-aware code
           proceeds to cache
         dictionary entries in it's
           own memory store.



           MultiDB-aware code
         ignores the object at the
           DATABASES setting,
               henceforth.
The way DATABASES should work.

        MultiDB-aware code asks for DB definition from
       the DATABASE_DEFINITION_PROVIDER class.




       If no provider has been specified, it falls back to
       the included default provider, which happens to
          look for a dictionary under the DATABASES
                              setting.




          Memory caching is LEFT UP TO THE
       PROVIDER. MultiDB-aware code does NOT do
               its own memory caching.
{% endrant %}
Right, back to DBMap
class DBMap(object):

    def __init__(self,
                 core_name='core',
                 core_engine='django.db.backends.postgresql_psycopg2',
                 core_user='',
                 core_password='',
                 core_host='localhost',
                 core_port='5432'):

        self.data = {'default':{'NAME':core_name,
                                'ENGINE':core_engine,
                                'USER':core_user,
                                'PASSWORD':core_password,
                                'HOST':core_host,
                                'PORT':core_port}}
More DBMap
def __getitem__(self,key):
    """
    Dictionary accessor.
    """
    if not key in self.data:
        self.load_db(key)

    return self.data[key]

def load_db(self,key):
    """
    Loads the specific database info.
    """
    from saaspire.accounts.models import Account
    try:
         account = Account.objects.get(slug=key)
         self.data[key] = {'NAME':account.db_name,
                           'ENGINE':account.db_engine,
                           'USER':account.db_user,
                           'PASSWORD':account.db_password,
                           'HOST':self.data['default']['HOST'],
                           'PORT':self.data['default']['PORT']}
    except Account.DoesNotExist:
         raise KeyError
Dynamic Creation of DBs
class Account(models.Model):

    def create_database(self):

        db_info = settings.DATABASES['default']

        host = db_info['HOST']
        cx_params = {'host':host}
        if db_info.get('USER',None):
            cx_params['user'] = db_info['USER']

        if db_info.get('PASSWORD',None):
            cx_params['password'] = db_info['PASSWORD']

        connection = psycopg2.connect(**cx_params)
        connection.set_isolation_level
(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
        cursor = connection.cursor()

        cursor.execute('CREATE DATABASE "%s" OWNER "%s"' % (slugify
(self.db_name), slugify(self.db_user),))

        # TO BE CONTINUED...
Dynamic Creation of DBs

class Account(models.Model):
    def create_database(self):

        # ...THE CONTINUATION...

        call_command('syncdb', database=self.db_name, interactive=False,
verbosity=0)

        settings.DATABASES.load_db(self.db_name) # Force DBMap to load
this database
        reload(south.db)
        call_command('migrate', database=self.db_name, interactive=False,
verbosity=0)
Questions?

Mais conteúdo relacionado

Mais procurados

Ms build – inline task
Ms build – inline taskMs build – inline task
Ms build – inline taskLearningTech
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2zfconfua
 
More tips n tricks
More tips n tricksMore tips n tricks
More tips n tricksbcoca
 
Intro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG CologneIntro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG CologneMarius Soutier
 
Python (Jinja2) Templates for Network Automation
Python (Jinja2) Templates for Network AutomationPython (Jinja2) Templates for Network Automation
Python (Jinja2) Templates for Network AutomationRick Sherman
 
Drupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in DrupalDrupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in DrupalBryan Braun
 
In-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascriptIn-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascriptThéodore Biadala
 
Django REST Framework
Django REST FrameworkDjango REST Framework
Django REST FrameworkLoad Impact
 
Why Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebWhy Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebBryan Helmig
 
Introduction to Ansible - (dev ops for people who hate devops)
Introduction to Ansible - (dev ops for people who hate devops)Introduction to Ansible - (dev ops for people who hate devops)
Introduction to Ansible - (dev ops for people who hate devops)Jude A. Goonawardena
 
Dmp hadoop getting_start
Dmp hadoop getting_startDmp hadoop getting_start
Dmp hadoop getting_startGim GyungJin
 
Intro To jQuery In Drupal
Intro To jQuery In DrupalIntro To jQuery In Drupal
Intro To jQuery In DrupalMatthew Farina
 
Celery - A Distributed Task Queue
Celery - A Distributed Task QueueCelery - A Distributed Task Queue
Celery - A Distributed Task QueueDuy Do
 
SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant   SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant Sencha
 
Deploy and Manage the Infrastructure Using Azure Resource Manager
Deploy and Manage the Infrastructure Using Azure Resource ManagerDeploy and Manage the Infrastructure Using Azure Resource Manager
Deploy and Manage the Infrastructure Using Azure Resource ManagerGlobalLogic Ukraine
 
Head First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & ApplicationHead First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & ApplicationJace Ju
 
Azure Expert Leading Camp UA - 2015
Azure Expert Leading Camp UA - 2015Azure Expert Leading Camp UA - 2015
Azure Expert Leading Camp UA - 2015Oleg Chorny
 

Mais procurados (20)

Ms build – inline task
Ms build – inline taskMs build – inline task
Ms build – inline task
 
Celery
CeleryCelery
Celery
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2
 
More tips n tricks
More tips n tricksMore tips n tricks
More tips n tricks
 
Intro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG CologneIntro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG Cologne
 
Python (Jinja2) Templates for Network Automation
Python (Jinja2) Templates for Network AutomationPython (Jinja2) Templates for Network Automation
Python (Jinja2) Templates for Network Automation
 
Drupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in DrupalDrupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in Drupal
 
In-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascriptIn-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascript
 
Django REST Framework
Django REST FrameworkDjango REST Framework
Django REST Framework
 
Intro to sbt-web
Intro to sbt-webIntro to sbt-web
Intro to sbt-web
 
Why Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebWhy Task Queues - ComoRichWeb
Why Task Queues - ComoRichWeb
 
Introduction to Ansible - (dev ops for people who hate devops)
Introduction to Ansible - (dev ops for people who hate devops)Introduction to Ansible - (dev ops for people who hate devops)
Introduction to Ansible - (dev ops for people who hate devops)
 
Dmp hadoop getting_start
Dmp hadoop getting_startDmp hadoop getting_start
Dmp hadoop getting_start
 
Intro To jQuery In Drupal
Intro To jQuery In DrupalIntro To jQuery In Drupal
Intro To jQuery In Drupal
 
Celery - A Distributed Task Queue
Celery - A Distributed Task QueueCelery - A Distributed Task Queue
Celery - A Distributed Task Queue
 
SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant   SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
 
Deploy and Manage the Infrastructure Using Azure Resource Manager
Deploy and Manage the Infrastructure Using Azure Resource ManagerDeploy and Manage the Infrastructure Using Azure Resource Manager
Deploy and Manage the Infrastructure Using Azure Resource Manager
 
Head First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & ApplicationHead First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & Application
 
Azure Expert Leading Camp UA - 2015
Azure Expert Leading Camp UA - 2015Azure Expert Leading Camp UA - 2015
Azure Expert Leading Camp UA - 2015
 
Django
DjangoDjango
Django
 

Destaque

Multi Tenancy With Python and Django
Multi Tenancy With Python and DjangoMulti Tenancy With Python and Django
Multi Tenancy With Python and Djangoscottcrespo
 
Developing Software As A Service App with Python & Django
Developing Software As A Service App with Python & DjangoDeveloping Software As A Service App with Python & Django
Developing Software As A Service App with Python & DjangoAllan Mangune
 
Moving from Django Apps to Services
Moving from Django Apps to ServicesMoving from Django Apps to Services
Moving from Django Apps to ServicesCraig Kerstiens
 
Django multi-tier
Django multi-tierDjango multi-tier
Django multi-tiersmirolo
 
Dev/Test Scenarios in the DevOps World
Dev/Test Scenarios in the DevOps WorldDev/Test Scenarios in the DevOps World
Dev/Test Scenarios in the DevOps WorldPranav Ainavolu
 
LCNUG 2015 - what's new for agile teams in TFS 2015
LCNUG 2015 -  what's new for agile teams in TFS 2015LCNUG 2015 -  what's new for agile teams in TFS 2015
LCNUG 2015 - what's new for agile teams in TFS 2015Angela Dugan
 
Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...
Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...
Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...MUG-Lyon Microsoft User Group
 
Best Practices for Front-End Django Developers
Best Practices for Front-End Django DevelopersBest Practices for Front-End Django Developers
Best Practices for Front-End Django DevelopersChristine Cheung
 
SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...
SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...
SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...Anusha Chickermane
 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC FrameworkBala Kumar
 
Scalable Django Architecture
Scalable Django ArchitectureScalable Django Architecture
Scalable Django ArchitectureRami Sayar
 
Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...
Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...
Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...MUG-Lyon Microsoft User Group
 

Destaque (16)

Multi Tenancy With Python and Django
Multi Tenancy With Python and DjangoMulti Tenancy With Python and Django
Multi Tenancy With Python and Django
 
Developing Software As A Service App with Python & Django
Developing Software As A Service App with Python & DjangoDeveloping Software As A Service App with Python & Django
Developing Software As A Service App with Python & Django
 
Moving from Django Apps to Services
Moving from Django Apps to ServicesMoving from Django Apps to Services
Moving from Django Apps to Services
 
Django multi-tier
Django multi-tierDjango multi-tier
Django multi-tier
 
Dev/Test Scenarios in the DevOps World
Dev/Test Scenarios in the DevOps WorldDev/Test Scenarios in the DevOps World
Dev/Test Scenarios in the DevOps World
 
Intro django
Intro djangoIntro django
Intro django
 
LCNUG 2015 - what's new for agile teams in TFS 2015
LCNUG 2015 -  what's new for agile teams in TFS 2015LCNUG 2015 -  what's new for agile teams in TFS 2015
LCNUG 2015 - what's new for agile teams in TFS 2015
 
Why Django
Why DjangoWhy Django
Why Django
 
Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...
Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...
Global Windows Azure Bootcamp : Samuel et Emilien Pécoul, Florent Pelet Legac...
 
Best Practices for Front-End Django Developers
Best Practices for Front-End Django DevelopersBest Practices for Front-End Django Developers
Best Practices for Front-End Django Developers
 
SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...
SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...
SaaSy maps - using django-tenants and geodjango to provide web-gis software-a...
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC Framework
 
Scaling Django
Scaling DjangoScaling Django
Scaling Django
 
Scalable Django Architecture
Scalable Django ArchitectureScalable Django Architecture
Scalable Django Architecture
 
Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...
Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...
Global Windows Azure Bootcamp : Pierre-Yves Fare Mobile Services. (sponsor An...
 

Semelhante a Django Multi-DB in Anger

mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introductionTse-Ching Ho
 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1DjangoCon2008
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance DjangoDjangoCon2008
 
Euruko 2009 - DataObjects
Euruko 2009 - DataObjectsEuruko 2009 - DataObjects
Euruko 2009 - DataObjectsDirkjan Bussink
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
 
DjangoCon 2010 Scaling Disqus
DjangoCon 2010 Scaling DisqusDjangoCon 2010 Scaling Disqus
DjangoCon 2010 Scaling Disquszeeg
 
Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Rabble .
 
Python magicmethods
Python magicmethodsPython magicmethods
Python magicmethodsdreampuf
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserHoward Lewis Ship
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyJaime Buelta
 
Behind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestBehind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestDaniel Hepper
 
Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School
Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School
Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School Elana Jacobs
 
Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Jan Helke
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsRichard Rodger
 
Zend Framework 2 - Basic Components
Zend Framework 2  - Basic ComponentsZend Framework 2  - Basic Components
Zend Framework 2 - Basic ComponentsMateusz Tymek
 
Automation with Ansible and Containers
Automation with Ansible and ContainersAutomation with Ansible and Containers
Automation with Ansible and ContainersRodolfo Carvalho
 

Semelhante a Django Multi-DB in Anger (20)

Django Pro ORM
Django Pro ORMDjango Pro ORM
Django Pro ORM
 
mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introduction
 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
 
Euruko 2009 - DataObjects
Euruko 2009 - DataObjectsEuruko 2009 - DataObjects
Euruko 2009 - DataObjects
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
 
DjangoCon 2010 Scaling Disqus
DjangoCon 2010 Scaling DisqusDjangoCon 2010 Scaling Disqus
DjangoCon 2010 Scaling Disqus
 
Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007
 
Python magicmethods
Python magicmethodsPython magicmethods
Python magicmethods
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
 
Behind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestBehind the curtain - How Django handles a request
Behind the curtain - How Django handles a request
 
Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School
Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School
Digital Ocean Presentation - Ruby Dev Stackup - The Flatiron School
 
Django at Scale
Django at ScaleDjango at Scale
Django at Scale
 
Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']Bye bye $GLOBALS['TYPO3_DB']
Bye bye $GLOBALS['TYPO3_DB']
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.js
 
20120816 nodejsdublin
20120816 nodejsdublin20120816 nodejsdublin
20120816 nodejsdublin
 
Zend Framework 2 - Basic Components
Zend Framework 2  - Basic ComponentsZend Framework 2  - Basic Components
Zend Framework 2 - Basic Components
 
Automation with Ansible and Containers
Automation with Ansible and ContainersAutomation with Ansible and Containers
Automation with Ansible and Containers
 
What's new in Django 1.2?
What's new in Django 1.2?What's new in Django 1.2?
What's new in Django 1.2?
 

Mais de Loren Davie

Blue Shift Marketing Plan
Blue Shift Marketing PlanBlue Shift Marketing Plan
Blue Shift Marketing PlanLoren Davie
 
Client management workshop for tech
Client management workshop for techClient management workshop for tech
Client management workshop for techLoren Davie
 
CAVE Language Presentation for AI Camp
CAVE Language Presentation for AI CampCAVE Language Presentation for AI Camp
CAVE Language Presentation for AI CampLoren Davie
 
Conversational Architecture: World IA Day 2016 NYC
Conversational Architecture: World IA Day 2016 NYCConversational Architecture: World IA Day 2016 NYC
Conversational Architecture: World IA Day 2016 NYCLoren Davie
 
Conversational Architecture, CAVE Language, Data Stewardship
Conversational Architecture, CAVE Language, Data StewardshipConversational Architecture, CAVE Language, Data Stewardship
Conversational Architecture, CAVE Language, Data StewardshipLoren Davie
 
Axilent Tool Talk from Breaking Development 2012
Axilent Tool Talk from Breaking Development 2012Axilent Tool Talk from Breaking Development 2012
Axilent Tool Talk from Breaking Development 2012Loren Davie
 
Django Environment
Django EnvironmentDjango Environment
Django EnvironmentLoren Davie
 
Newforms Admin 101
Newforms Admin 101Newforms Admin 101
Newforms Admin 101Loren Davie
 
Model Inheritance
Model InheritanceModel Inheritance
Model InheritanceLoren Davie
 

Mais de Loren Davie (11)

Blue Shift Marketing Plan
Blue Shift Marketing PlanBlue Shift Marketing Plan
Blue Shift Marketing Plan
 
Client management workshop for tech
Client management workshop for techClient management workshop for tech
Client management workshop for tech
 
CAVE Language Presentation for AI Camp
CAVE Language Presentation for AI CampCAVE Language Presentation for AI Camp
CAVE Language Presentation for AI Camp
 
Conversational Architecture: World IA Day 2016 NYC
Conversational Architecture: World IA Day 2016 NYCConversational Architecture: World IA Day 2016 NYC
Conversational Architecture: World IA Day 2016 NYC
 
Conversational Architecture, CAVE Language, Data Stewardship
Conversational Architecture, CAVE Language, Data StewardshipConversational Architecture, CAVE Language, Data Stewardship
Conversational Architecture, CAVE Language, Data Stewardship
 
Axilent Tool Talk from Breaking Development 2012
Axilent Tool Talk from Breaking Development 2012Axilent Tool Talk from Breaking Development 2012
Axilent Tool Talk from Breaking Development 2012
 
Django Intro
Django IntroDjango Intro
Django Intro
 
Django Environment
Django EnvironmentDjango Environment
Django Environment
 
Newforms Admin 101
Newforms Admin 101Newforms Admin 101
Newforms Admin 101
 
App Engine
App EngineApp Engine
App Engine
 
Model Inheritance
Model InheritanceModel Inheritance
Model Inheritance
 

Último

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 

Último (20)

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 

Django Multi-DB in Anger

  • 1.
  • 2. MultiDB In Anger Professional Driver. Closed Course.
  • 3. Hi. Sean OConnor in background, with superior monitor. “Checkpoint Charlie” T- Shirt World Headquarters
  • 4.
  • 5. Django MultiDB As It Was Probably Intended
  • 6. The Legacy DB Problem Legacy DB New DB, that you are built for New Unable to Web App Eliminate. :( Django Website
  • 7. Django ORM, Before. ORM API Database Backend Python Database Driver RDBMS
  • 8. MultiDB Mode ORM API DB Routing DB DB DB Definition Definition Definition Database Database Database Backend Backend Backend Python Python Python Database Database Database Driver Driver Driver RDBMS RDBMS RDBMS
  • 9. Out of the Box • Database definitions. • --database= • Database Routers. • using(), using=
  • 10. DB Definitions settings.py DATABASES = { 'default': { 'NAME': 'app_data', 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'USER': 'postgres_user', 'PASSWORD': 's3krit' }, 'users': { 'NAME': 'user_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'priv4te' } }
  • 11. --database= ./manage.py syncdb ./manage.py syncdb --database=legacy ./manage.py migrate ./manage.py migrate --database=legacy
  • 12. Database Routers class MyAppRouter(object): """A router to control all database operations on models in the myapp application""" def db_for_read(self, model, **hints): "Point all operations on myapp models to 'other'" if model._meta.app_label == 'myapp': return 'other' return None def db_for_write(self, model, **hints): "Point all operations on myapp models to 'other'" if model._meta.app_label == 'myapp': return 'other' return None
  • 13. Database Routers settings.py DATABASE_ROUTERS = [‘path.to.MyAppRouter’,‘path.to.OtherRouter’]
  • 14. API: “using” Author.objects.using(‘other’).all() p = Person(name=‘Fred’) p.save(using=‘db0’) p.save(using=‘db1’)
  • 15. And now, the real world... MultiDB Meets
  • 16. The Multi-Tenant Hydra • SaaS • Multiple accounts on a cluster. • Each account with “substantial” data. • Need to think about sharding.
  • 17. OMG It’s Full of Stars Account DB Account Account DB DB Account Core Account DB DB DB Account Account DB DB Account DB
  • 18. Core vs. Account • Core DB • Account DBs • Account Data • Everything Else • User Data • Immutable Data
  • 19. More Requirements • Easy, declarative specification of core vs account for any model. • No explicit DB references in code. • Must route account models to correct account db. • Must support web and Celery task usage.
  • 20. ...and even worse: • No a priori knowledge of account databases. Seriously. Oh, boy...
  • 22. Declarative Model Routing class ApplicationSeat(models.Model): """ A seat for an application. """ app = models.ForeignKey(Application) user = models.ForeignKey (UserProfile,related_name='application_seats') global_model = True def __unicode__(self): return '%s - %s' % (unicode(self.app),unicode(self.user)) class Meta: unique_together = (('app','user'),)
  • 23. Declarative Model Routing class AccountRouter(object): """ Routes models to account database, unless they are flagged global. """ def _is_saaspire(self,model): return model.__module__.startswith('saaspire') def _global(self,model): return hasattr(model,'global_model') and model.global_model
  • 24. Routing to Core class AccountRouter(object): # ... def db_for_read(self,model,**hints): """ Gets the db for read. """ from saaspire.accounts.utils import current_account if self._is_saaspire(model): if self._global(model): return 'default' else: self._init_dbs() ca = current_account() if ca: return ca.slug else: return None else: return None
  • 25. Routing to Account class AccountRouter(object): # ... def db_for_read(self,model,**hints): """ Gets the db for read. """ from saaspire.accounts.utils import current_account if self._is_saaspire(model): if self._global(model): return 'default' else: self._init_dbs() ca = current_account() if ca: return ca.slug else: return None else: return None
  • 26. What account am I using? def current_account(): """ Gets the current account. """ from environment import env # Look for explicit account specification if hasattr(env,'account') and env.account: return env.account # ... # Look for current user if hasattr(env,'user') and not env.user.is_anonymous(): profile = env.user.get_profile() if profile: return profile.account return None
  • 27. Warning: The following scene contains threadlocals.
  • 28.
  • 29. Django-Environment Start Values associated with HTTP Request threadlocal "env" Django- View Environment executes Environment Threadlocal is Generators cleared. Stop
  • 30. What account am I using? main.env from environment.standard import RequestAttributeGenerator from saaspire.core.envgen import AccountGenerator, InstanceGenerator entries = { 'user':RequestAttributeGenerator('user'), 'account':AccountGenerator(), 'instance':InstanceGenerator(), }
  • 31. What account am I using? class AccountGenerator(object): """ Populates the environment with the current account. """ def generate(self,key,request): """ Generates the variable. """ if not request.user.is_anonymous(): return request.user.get_profile().account else: return None
  • 32. What account am I using? def current_account(): """ Gets the current account. """ from environment import env # Look for explicit account specification if hasattr(env,'account') and env.account: return env.account
  • 33. But what about Celery? • Celery: An async message queue. • No HTTP request/response cycle. • Django-environment won’t work.
  • 34. use_account() context manager @periodic_task(run_every=timedelta(minutes=60)) def run_proactive_service_subinferences(): for account in Account.objects.active(): with use_account(account.name): # etc...
  • 35. use_account() context manager class use_account(object): """ Context manager that sets a specific account. """ def __init__(self,account_name): from saaspire.accounts.models import Account self.account = Account.objects.get(Q(name=account_name) | Q (slug=account_name)) self.current_account = None def __enter__(self): """ Called at beginning of with block. """ from environment import env if hasattr(env,'account'): self.current_account = env.account env.account = self.account def __exit__(self,*args,**kwargs): """ Called at end of with block. """ from environment import env env.account = self.current_account
  • 36. No a priori knowledge of account databases.
  • 37. This is cached in memory. DATABASES = { 'default': { 'NAME': 'app_data', 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'USER': 'postgres_user', 'PASSWORD': 's3krit' }, 'users': { 'NAME': 'user_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'priv4te' } }
  • 38. What we need. There is no Database "X" is database "X". automatically created. Someone Account "X" traffic signs up for automatically Saaspire routed to DB "X". account "X".
  • 39. DBMap settings.py from saaspire.core.db import DBMap DATABASES = DBMap() # Dictionary-like thingie
  • 41. The way DATABASES works. MultiDB-aware code looks for a dictionary assigned to DATABASES setting. MultiDB-aware code proceeds to cache dictionary entries in it's own memory store. MultiDB-aware code ignores the object at the DATABASES setting, henceforth.
  • 42. The way DATABASES should work. MultiDB-aware code asks for DB definition from the DATABASE_DEFINITION_PROVIDER class. If no provider has been specified, it falls back to the included default provider, which happens to look for a dictionary under the DATABASES setting. Memory caching is LEFT UP TO THE PROVIDER. MultiDB-aware code does NOT do its own memory caching.
  • 44. Right, back to DBMap class DBMap(object): def __init__(self, core_name='core', core_engine='django.db.backends.postgresql_psycopg2', core_user='', core_password='', core_host='localhost', core_port='5432'): self.data = {'default':{'NAME':core_name, 'ENGINE':core_engine, 'USER':core_user, 'PASSWORD':core_password, 'HOST':core_host, 'PORT':core_port}}
  • 45. More DBMap def __getitem__(self,key): """ Dictionary accessor. """ if not key in self.data: self.load_db(key) return self.data[key] def load_db(self,key): """ Loads the specific database info. """ from saaspire.accounts.models import Account try: account = Account.objects.get(slug=key) self.data[key] = {'NAME':account.db_name, 'ENGINE':account.db_engine, 'USER':account.db_user, 'PASSWORD':account.db_password, 'HOST':self.data['default']['HOST'], 'PORT':self.data['default']['PORT']} except Account.DoesNotExist: raise KeyError
  • 46. Dynamic Creation of DBs class Account(models.Model): def create_database(self): db_info = settings.DATABASES['default'] host = db_info['HOST'] cx_params = {'host':host} if db_info.get('USER',None): cx_params['user'] = db_info['USER'] if db_info.get('PASSWORD',None): cx_params['password'] = db_info['PASSWORD'] connection = psycopg2.connect(**cx_params) connection.set_isolation_level (psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) cursor = connection.cursor() cursor.execute('CREATE DATABASE "%s" OWNER "%s"' % (slugify (self.db_name), slugify(self.db_user),)) # TO BE CONTINUED...
  • 47. Dynamic Creation of DBs class Account(models.Model): def create_database(self): # ...THE CONTINUATION... call_command('syncdb', database=self.db_name, interactive=False, verbosity=0) settings.DATABASES.load_db(self.db_name) # Force DBMap to load this database reload(south.db) call_command('migrate', database=self.db_name, interactive=False, verbosity=0)