Pytanie Python DB-API: jak radzić sobie z różnymi stylami?


Wdrażam klasę ontologii Pythona, która używa zaplecza bazy danych do przechowywania i wyszukiwania ontologii. Schemat bazy danych jest poprawiony (określony wcześniej), ale nie wiem, jaki typ silnika bazy danych jest używany. Mogę jednak polegać na tym, że interfejs Pythona silnika bazy danych korzysta z Python DB-API 2.0 (PEP 249). Prostym pomysłem jest umożliwienie użytkownikowi przejścia na zgodność z PEP 249 Connection obiekt do konstruktora mojej ontologii, który następnie użyje różnych zakodowanych zapytań SQL do zapytania do bazy danych:

class Ontology(object):
    def __init__(self, connection):
        self.connection = connection

    def get_term(self, term_id):
        cursor = self.connection.cursor()
        query = "SELECT * FROM term WHERE id = %s"
        cursor.execute(query, (term_id, ))
        [...]

Mój problem polega na tym, że różne bazy danych mogą obsługiwać różne znaczniki parametrów w zapytaniach, zdefiniowanych przez paramstyle atrybut modułu zaplecza. Na przykład, jeśli paramstyle = 'qmark', interfejs obsługuje styl znaku zapytania (SELECT * FROM term WHERE id = ?); paramstyle = 'numeric' oznacza numeryczny, pozycyjny styl (SELECT * FROM term WHERE id = :1); paramstyle = 'format' oznacza styl ciągów w formacie ANSI C (SELECT * FROM term WHERE id = %s). Jeśli chcę, aby moja klasa była w stanie obsłużyć różne bazy danych, wydaje mi się, że muszę przygotować się na wszystkie style znaczników parametrów. Wydaje się, że pokonałem cały cel wspólnego API DB dla mnie, ponieważ nie mogę użyć tego samego sparametryzowanego zapytania z różnymi bazami danych bazy danych.

Czy jest jakiś sposób obejścia tego, a jeśli tak, jakie jest najlepsze podejście? Interfejs API bazy danych nie określa istnienia ogólnej funkcji przechodzenia, dzięki której mogę odseparować moje wartości w zapytaniu, więc ręczne wykonywanie instrukcji nie jest opcją. Nie chcę dodawać dodatkowej zależności do projektu przy użyciu jeszcze wyższego poziomu abstrakcji (na przykład SQLAlchemy).


12
2017-09-30 08:51


pochodzenie




Odpowiedzi:


Ściśle rzecz biorąc, problem nie jest spowodowany przez API DB pozwalające na to, ale przez różne bazy danych, które używają różnych składni SQL. Moduł API DB przekazuje dokładny ciąg zapytania do bazy danych wraz z parametrami. "Rozstrzyganie" znaczników parametrów odbywa się przez samą bazę danych, a nie przez moduł DB API.

Oznacza to, że jeśli chcesz rozwiązać ten problem, musisz wprowadzić trochę wyższy poziom abstrakcji. Jeśli nie chcesz dodawać dodatkowych zależności, musisz to zrobić samodzielnie. Zamiast ręcznie wymieniać i zastępować, można spróbować dynamicznie zamienić znaczniki parametrów w łańcuchu zapytania na pożądane znaczniki parametrów, w oparciu o paramformę modułu zaplecza. Następnie przeprowadź łańcuch, ze znacznikami parametrów do bazy danych. Na przykład, możesz użyć '% s' wszędzie i użyć zamiany ciągu Pythona w celu zamiany '% s' na ": 1", ": 2" itd., Jeśli db używa stylu "numerycznego" itd. ..


1
2017-09-30 11:47



Hmm, nie jestem w 100% pewien co do modułu DB API przekazującego dokładny ciąg zapytania do bazy danych; na przykład, BaseCursor.execute w MySQLdb moduł używa query = query % db.literal(args) sformatować jawnie ciąg zapytania przed wysłaniem go do silnika bazy danych. To może nie być prawdą w przypadku innych silników baz danych. W każdym razie, jestem także skłonny do wymiany %s z innymi stylami znaczników, w locie, ale zastanawiałem się, czy istnieje prostsze rozwiązanie. Jeśli nikt nie wymyśli niczego, z przyjemnością przyjmuję twoją odpowiedź. - Tamás
"Moduł API DB przekazuje dokładny ciąg zapytania do bazy danych wraz z parametrami."Nie sądzę, żeby tak było, jeśli spojrzeć na to Specyfikacja sieci PostgreSQL na przykład, gdy jest używany, używają zapytania param $1, $2, ... jako posiadacze miejsc, które nie są żadnymi z nich Python paramstyles. Oczywiście, ciągi zapytań są modyfikowane przed wysłaniem, tak czy inaczej, bardziej w przypadku stylu param, który bazuje na dyktowaniu (z nazwami). - Bruno


  • Ten przepis Pythona może być w stanie pomóc. Wprowadza dodatkową warstwę abstrakcji, aby owijać parametry samodzielnie Param klasa.

  • The PyDal projekt może być również bliższy temu, co próbujesz osiągnąć: "PyDal pozwala używać tych samych typów paramstyle i datetime z dowolnym modułem, który jest zgodny z DBAPI 2.0. Ponadto można konfigurować style i typy datetime."


5
2018-03-03 13:41



Obie te opcje wyglądają dobrze, ale zauważ, że wydają się być stare. Te strony internetowe kodu źródłowego zawierają najnowsze komentarze / aktualizacje z lat 2004-2007. To może być w porządku. Po prostu bądź świadomy. - IcarusNM


Nie chcę dodawać dodatkowej zależności do projektu za pomocą   jeszcze wyższy poziom abstrakcji (na przykład SQLAlchemy).

To źle, ponieważ SQLAlchemy byłby idealnym rozwiązaniem tego problemu. Teoretycznie DB-API 2.0 jest zbudowany, aby oferować tego rodzaju elastyczność. Wymagałoby to jednak każdego programisty sterowników (dla Oracle, MySQLdb, PostgreSQL, itd.) W celu implementacji wszystkich różnych stylów w swoich sterownikach. Nie robią tego. Więc utknąłeś z "preferowanym" stylem dla każdego silnika bazy danych.

Jeśli odmówisz używania SQLAlchemy lub innej wyższej warstwy abstrakcji lub nowoczesnej biblioteki klasy MVC, tak, musisz napisać o tym swój wyższy poziom abstrakcji. Nie polecam tego, mimo że jest to tutaj wybrane rozwiązanie. Stajesz w obliczu diabelskich szczegółów i tracisz czas na wykrywanie błędów, które inni już rozwiązali.

Nie należy postrzegać zależności zewnętrznej biblioteki jako czegoś złego. Jeśli to twoje podejście do Pythona, stracisz dostęp do niektórych z najpotężniejszych funkcji tego języka.

Wybierz swoją truciznę.


0
2018-04-22 20:16