2011-07-05 21 views
25

Oceniłem django i zastanawiałem się, czy jest to możliwe. Sprawdziłem już wiele standardowych dokumentów baz danych, więc nie kieruj mnie do tego, ponieważ ten przypadek użycia nie jest wymieniony, o ile mogę to zrozumieć. Jeśli się mylę, to odbieram :)Django wielu i dynamicznych baz danych

Potrzebuję jednej głównej bazy danych, w której będzie większość modeli mojej aplikacji, jednak jedna z aplikacji będzie musiała dynamicznie tworzyć bazy danych, będą to bazy danych specyficzne dla klienta.

Ścieżka do bazy danych (planuję użyć sqlite) zostanie zapisana w głównej bazie danych, więc kursor będzie musiał zostać zmieniony, ale model pozostanie taki sam.

Z radością przyjmuję wszelkie przemyślenia na temat sposobów osiągnięcia tego celu?

+0

Dlaczego MUSISZ korzystać z wielu baz danych? Czy istnieje powód, dla którego nie można dostosować schematu (modeli) aplikacji, aby przechowywać informacje dla każdego klienta? Posiadanie wielu baz danych dla każdego klienta jest wysoce nieregularne. –

+0

Próbuję określić odpowiednią architekturę w tej chwili. NIE MAMY używać wielu baz danych, ale jest to jedna z opcji świadczenia przenośnego, online i offline świadczenia usług. I w tym celu chciałbym się dowiedzieć, czy jest to możliwe, jest to dość proste koncepcyjnie, ale wiem, że w praktyce wspieranie tego w ogólnych ramach mogłoby być trudne, więc pomyślałem, że zobaczę, czy ktoś wcześniej coś takiego zrobił. – nickjb

+1

możliwy duplikat [Django: dynamiczny plik bazy danych] (http://stackoverflow.com/questions/14254315/django-dynamic-database-file) (Uwaga: powiązane pytanie wydaje się być właściwym rozwiązaniem, które nie wymaga obejście ponownego uruchomienia serwera po dodaniu/zmianie/usunięciu nowej bazy danych) – mgibsonbr

Odpowiedz

24

Otwieram pod numerem "You should not edit settings at runtime".

Powiedziawszy to, mam dokładnie ten sam problem, w którym chcę utworzyć unikalną bazę danych dla każdego użytkownika. Powodem tego jest oferowanie użytkownikowi możliwości zapisu/dostępu do/z bazy danych nieprzechowywanej na moim serwerze, co pociąga za sobą posiadanie wielu baz danych, a więc jednego dla każdego użytkownika.

Ta odpowiedź NIE jest zalecanym sposobem na osiągnięcie pożądanego celu. Chciałbym usłyszeć od django-guru, jak najlepiej podejść do tego problemu. Jednak jest to rozwiązanie, z którego korzystałem i jak dotąd dobrze się sprawdziło. Używam programu sqlite, ale można go łatwo zmodyfikować dla dowolnej z baz danych.

Podsumowując, jest to proces:

  1. Dodaj nową bazę danych do ustawień (przy starcie)
  2. Utwórz plik do przechowywania tych ustawień do przeładunku przy ponownym uruchomieniu serwera (przy starcie)
  3. uruchomić skrypt, który ładuje zapisane pliki ustawień (gdy serwer zostanie ponownie uruchomiony)

teraz, jak to osiągnąć:

1) Po pierwsze, po utworzeniu nowego użytkownika, tworzę nową bazę danych w ustawieniach. Ten kod jest w moim widoku miejscem tworzenia nowych użytkowników.

from YOUR_PROJECT_NAME import settings 
database_id = user.username #just something unique 
newDatabase = {} 
newDatabase["id"] = database_id 
newDatabase['ENGINE'] = 'django.db.backends.sqlite3' 
newDatabase['NAME'] = '/path/to/db_%s.sql' % database_id 
newDatabase['USER'] = '' 
newDatabase['PASSWORD'] = '' 
newDatabase['HOST'] = '' 
newDatabase['PORT'] = '' 
settings.DATABASES[database_id] = newDatabase 
save_db_settings_to_file(newDatabase) #this is for step 2) 

Ten skrypt ładuje ustawienia bazy danych "w czasie wykonywania" do ustawień projektu django. Jeśli jednak serwer zostanie zrestartowany, ta baza danych nie będzie już w ustawieniach.

2) Aby ułatwić ponowne ładowanie tych ustawień automatycznie po każdym zrestartowaniu serwera, tworzę plik dla każdej bazy danych, która zostanie załadowana przy każdym uruchomieniu serwera. Tworzenie tego pliku jest wykonywana przez funkcję save_db_settings_to_file:

def save_db_settings_to_file(db_settings): 
    path_to_store_settings = "/path/to/your/project/YOUR_PROJECT_NAME/database_settings/" 
    newDbString = """ 
DATABASES['%(id)s'] = { 
    'ENGINE': '%(ENGINE)s', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 
    'NAME': '%(NAME)s',      # Or path to database file if using sqlite3. 
    'USER': '',      # Not used with sqlite3. 
    'PASSWORD': '',     # Not used with sqlite3. 
    'HOST': '',      # Set to empty string for localhost. Not used with sqlite3. 
    'PORT': '',      # Set to empty string for default. Not used with sqlite3. 
} 
    """ % db_settings 
    file_to_store_settings = os.path.join(path_to_store_settings, db_settings['id'] + ".py") 
    write_file(file_to_store_settings, newDbString) #psuedocode for compactness 

3) Aby faktycznie załadować te ustawienia, gdy serwer jest uruchomiony, dodać jedną linię do samego dołu /path/to/your/project/YOUR_PROJECT_NAME/settings.py, który ładuje każdy plik w folderze Ustawienia i uruchamia ją, powodując załadowanie szczegółów bazy danych do ustawień.

import settings_manager 

Następnie import settings_manager załaduje plik na /path/to/your/project/YOUR_PROJECT_NAME/settings_manager.py, który zawiera następujący kod:

from settings import DATABASES 
import os 

path_to_store_settings = "/path/to/your/project/YOUR_PROJECT_NAME/database_settings/" 
for fname in os.listdir(path_to_settings): 
    full_path = os.path.join(path_to_settings, fname) 
    f = open(full_path) 
    content = f.read() 
    f.close() 
    exec(content) #you'd better be sure that the file doesn't contain anything malicious 

pamiętać, że można umieścić ten kod bezpośrednio na dnie settings.py zamiast instrukcji import , ale użycie instrukcji import utrzymuje poziom abstrakcji pliku settings.py zgodny.

Jest to wygodny sposób na załadowanie każdego ustawienia bazy danych, ponieważ aby usunąć bazę danych z ustawień, wystarczy usunąć plik ustawień, a przy następnym uruchomieniu serwera nie załaduje tych danych do ustawień , a baza danych nie będzie dostępna.

Jak już powiedziałem, to działa i odniosłem sukces, wykorzystując go do tej pory, ale nie jest to idealne rozwiązanie. Byłbym wdzięczny, gdyby ktoś mógł zamieścić lepsze rozwiązanie.

Co znajduje się źle o nim:

  • To wyraźnie przeciwstawia porady od zespołu Django nie zmodyfikować ustawienia przy starcie. Nie znam powodu, dla którego udzielono tej porady.
  • Używa instrukcji exec do załadowania danych do ustawień. To powinno być OK, ale jeśli dostaniesz jakiś uszkodzony lub złośliwy kod w jednym z tych plików, będziesz smutną pandą.

Należy pamiętać, że nadal używam domyślnej bazy danych dla danych autoryzacji i sesji, ale wszystkie dane z moich własnych aplikacji są przechowywane w bazie danych użytkownika.

+0

Przyszłam z innym rozwiązaniem, mimo że zaimplementowałem twoją metodę (za pomocą plików) i moją, używając samej bazy danych jako magazynu dla tych plików . Ostatnia linia pliku settings.py ładuje wszystkie modele zawierające definicje bazy danych i dodaje je do ustawienia DATABASE w Django. –

+2

Możesz uczynić go bardziej eleganckim niż plik tekstowy, jeśli piszesz połączenia db w głównej bazie danych (tej, którą zarządzasz użytkownikami). – JulienD

7

Aby zwiększyć odpowiedź @ thedawnrider, w niektórych przypadkach edycja settings.DATABASES może nie wystarczyć. Może być bardziej niezawodny, aby edytować django.db.connections.databases, który służy jako pamięć podręczna i otoki wokół settings.DATABASES.

np.

from django.db import connections 
database_id = user.username #just something unique 
newDatabase = {} 
newDatabase["id"] = database_id 
newDatabase['ENGINE'] = 'django.db.backends.sqlite3' 
newDatabase['NAME'] = '/path/to/db_%s.sql' % database_id 
newDatabase['USER'] = '' 
newDatabase['PASSWORD'] = '' 
newDatabase['HOST'] = '' 
newDatabase['PORT'] = '' 
connections.databases[database_id] = newDatabase 
Powiązane problemy