sql >> Databáze >  >> RDS >> Mysql

Aplikace Django pro více nájemců:změna databázového připojení na žádost?

Udělal jsem něco podobného, ​​co je nejblíže bodu 1, ale místo použití middlewaru k nastavení výchozího připojení se používají databázové routery Django. To umožňuje aplikační logice používat řadu databází, pokud je to vyžadováno pro každý požadavek. Je na aplikační logice, aby zvolila vhodnou databázi pro každý dotaz, a to je velká nevýhoda tohoto přístupu.

S tímto nastavením jsou všechny databáze uvedeny v settings.DATABASES , včetně databází, které mohou být sdíleny mezi zákazníky. Každý model, který je specifický pro zákazníka, je umístěn v aplikaci Django, která má specifický štítek aplikace.

např. Následující třída definuje model, který existuje ve všech zákaznických databázích.

class MyModel(Model):
    ....
    class Meta:
        app_label = 'customer_records'
        managed = False

Databázový router je umístěn v settings.DATABASE_ROUTERS řetěz pro směrování databázového požadavku podle app_label , něco takového (není úplný příklad):

class AppLabelRouter(object):
    def get_customer_db(self, model):
        # Route models belonging to 'myapp' to the 'shared_db' database, irrespective
        # of customer.
        if model._meta.app_label == 'myapp':
            return 'shared_db'
        if model._meta.app_label == 'customer_records':
            customer_db = thread_local_data.current_customer_db()
            if customer_db is not None:
                return customer_db

            raise Exception("No customer database selected")
        return None

    def db_for_read(self, model, **hints):
        return self.get_customer_db(model, **hints)

    def db_for_write(self, model, **hints):
        return self.get_customer_db(model, **hints)

Speciální částí tohoto routeru je thread_local_data.current_customer_db() volání. Před použitím routeru musí volající/aplikace nastavit aktuální databázi zákazníka v thread_local_data . K tomuto účelu lze použít kontextového manažera Pythonu k odeslání/vypnutí aktuální databáze zákazníků.

Když je toto vše nakonfigurováno, kód aplikace pak vypadá nějak takto, kde UseCustomerDatabase je kontextový manažer, který vloží/zobrazí název aktuální zákaznické databáze do thread_local_data takže thread_local_data.current_customer_db() při konečném zásahu směrovače vrátí správný název databáze:

class MyView(DetailView):
    def get_object(self):
        db_name = determine_customer_db_to_use(self.request) 
        with UseCustomerDatabase(db_name):
            return MyModel.object.get(pk=1)

Toto je již poměrně složité nastavení. Funguje to, ale pokusím se shrnout, v čem vidím výhody a nevýhody:

Výhody

  • Výběr databáze je flexibilní. Umožňuje použití více databází v jednom dotazu, přičemž v požadavku lze použít jak databáze specifické pro zákazníka, tak sdílené databáze.
  • Výběr databáze je explicitní (nejsem si jistý, zda je to výhoda nebo nevýhoda). Pokud se pokusíte spustit dotaz, který zasáhne databázi zákazníků, ale aplikace žádný nevybere, dojde k výjimce označující chybu programování.
  • Použití databázového routeru umožňuje existenci různých databází na různých hostitelích, namísto spoléhání se na USE db; příkaz, který odhaduje, že všechny databáze jsou přístupné prostřednictvím jediného připojení.

Nevýhody

  • Nastavení je složité a jeho fungování zahrnuje poměrně málo vrstev.
  • Potřeba a použití místních dat vlákna je nejasná.
  • Zobrazení jsou poseta kódem pro výběr databáze. To by se dalo abstrahovat pomocí třídních pohledů k automatickému výběru databáze na základě parametrů požadavku stejným způsobem, jakým by middleware zvolil výchozí databázi.
  • Správce kontextu pro výběr databáze musí být zabalený kolem sady dotazů takovým způsobem, aby byl správce kontextu při vyhodnocení dotazu stále aktivní.

Návrhy

Pokud chcete flexibilní přístup k databázi, navrhoval bych použít databázové routery Django. Použijte Middleware nebo pohled Mixin, který automaticky nastaví výchozí databázi pro připojení na základě parametrů požadavku. Možná se budete muset uchýlit k místním datům vláken a uložit výchozí databázi, která se má použít, takže když je směrovač zasažen, věděl, do které databáze má směrovat. To umožňuje Djangu používat svá stávající trvalá připojení k databázi (která může být v případě potřeby umístěna na různých hostitelích) a vybrat databázi k použití na základě směrování nastaveného v požadavku.

Tento přístup má také tu výhodu, že databázi pro dotaz lze v případě potřeby přepsat pomocí QuerySet using() vyberte jinou než výchozí databázi.



  1. Použití PIVOT v SQL Server 2008

  2. MYSQL - Seskupit podle limitu

  3. Vytváření aktivačních událostí auditu na serveru SQL Server

  4. Postgres - Funkce pro návrat průsečíku 2 POLE?