Wróć do katalogu
Season 37 7 Odcinki 26 min 2026

SQLAlchemy

v2.0 — Edycja 2026. Kompleksowy kurs audio o SQLAlchemy, obejmujący zarówno Core, jak i ORM, stworzony z myślą o wersji 2.0 wydanej w 2026 roku. Dowiedz się, jak mapować swoją domenę, strukturyzować aplikację, zarządzać transakcjami za pomocą Session i skutecznie wykonywać zapytania.

Bazy danych ORM Python Core
SQLAlchemy
Teraz odtwarzane
Click play to start
0:00
0:00
1
Podstawy: Czym jest SQLAlchemy i ORM?
Witamy w SQLAlchemy. Przedstawiamy główną architekturę, wyjaśniając różnicę między zorientowanym na schemat Core a zorientowanym na domenę ORM. Poznasz podstawową terminologię i dowiesz się, dlaczego potrzebujesz ORM.
3m 41s
2
Engine: Twoja brama do bazy danych
Każda aplikacja SQLAlchemy zaczyna się od Engine. Dowiedz się, jak nawiązać połączenie, czym jest pula połączeń oraz jak dialekty i DBAPI łączą Cię z bazą danych.
3m 53s
3
Mapowanie domeny: Declarative Base i modele
Automatycznie tłumacz swoje klasy Pythona na tabele bazy danych. Omawiamy DeclarativeBase, typy Mapped oraz to, jak mapped_column buduje metadane Twojej bazy danych.
4m 04s
4
Układ projektu: Strukturyzacja Twojej aplikacji
Organizacja kodu ma znaczenie. Poznaj najlepsze praktyki strukturyzacji repozytorium projektu SQLAlchemy, aby Twój Engine, modele i sesje pozostały przejrzyste i łatwe w utrzymaniu.
3m 31s
5
Session: Opanowanie Unit of Work
Odkryj wzorzec Unit of Work poprzez Session w ORM. Dowiedz się, jak dodawać obiekty, kiedy występują operacje flush i jak perfekcyjnie wykonywać commit transakcji.
3m 55s
6
Pobieranie danych: Nowoczesna konstrukcja Select
Pobieraj dane dokładnie tak, jak tego potrzebujesz. Odkrywamy ujednoliconą konstrukcję select() w SQLAlchemy 2.0, filtrowanie za pomocą where() oraz wykonywanie zapytań przy użyciu Session.
3m 05s
7
Łączenie elementów: Relacje i JOINy
Płynnie łącz swoje tabele. Dowiedz się, jak konfigurować relacje, używać back_populates i automatycznie zarządzać SQL JOINs w powiązanych modelach.
3m 51s

Odcinki

1

Podstawy: Czym jest SQLAlchemy i ORM?

3m 41s

Witamy w SQLAlchemy. Przedstawiamy główną architekturę, wyjaśniając różnicę między zorientowanym na schemat Core a zorientowanym na domenę ORM. Poznasz podstawową terminologię i dowiesz się, dlaczego potrzebujesz ORM.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 1 z 7. Czy zdarzyło Ci się kiedyś przypadkowo dropnąć tabelę albo zepsuć query przez literówkę w raw SQL stringu? Query budowane przez konkatenację stringów są kruche, trudne w utrzymaniu i stanowią zagrożenie dla bezpieczeństwa. W tym odcinku omówimy rozwiązanie: Podstawy: Czym jest SQLAlchemy i ORM? Głównym problemem, z jakim borykają się developerzy piszący aplikacje korzystające z baz danych, jest to, że Python i relacyjne bazy danych myślą inaczej. Python używa obiektów. Obiekty mają stan, zachowanie i złożone relacje. Relacyjne bazy danych używają tabel, kolumn i wierszy. Opierają się na primary i foreign keys. Zapisanie obiektu Pythona w tabeli bazy danych wymaga przetłumaczenia jego stanu na SQL statement. Pobranie go z powrotem wymaga parsowania wierszy i wypełnienia danymi nowego obiektu. To tarcie nazywa się object-relational impedance mismatch. Pisanie raw SQL stringów, żeby obsłużyć to tłumaczenie, jest żmudne i podatne na błędy. SQLAlchemy to toolkit SQL dla Pythona, zaprojektowany, aby rozwiązać dokładnie ten problem. W przeciwieństwie do niektórych narzędzi, które próbują ukryć bazę danych za ścianą abstrakcji, SQLAlchemy stawia na SQL-a. Zapewnia solidny, pythonowy workflow, który generuje optymalny SQL, pozostawiając Ci pełną kontrolę. Architektura jest podzielona na dwie odrębne części: Core i ORM. SQLAlchemy Core to fundament. Jest command-oriented i schema-oriented. Oznacza to, że pracujesz bezpośrednio z tabelami, kolumnami i wierszami bazy danych, ale robisz to za pomocą obiektów Pythona zamiast raw text stringów. Jeśli chcesz pobrać dane, wywołujesz metodę select. Jeśli chcesz filtrować, chainujesz metodę where. Eliminuje to ryzyko błędów składniowych wynikających z konkatenacji stringów i chroni przed SQL injection. Core to w gruncie rzeczy język wyrażeń SQL. ORM, czyli Object Relational Mapper, działa na wierzchu Core'a. Podczas gdy Core jest schema-oriented, ORM jest state-oriented i domain-oriented. Oto kluczowa sprawa. Dzięki ORM-owi przestajesz myśleć o tabelach i wierszach, a zaczynasz myśleć o modelu domeny aplikacji. Definiujesz standardową klasę Pythona, na przykład klasę User. Konfigurujesz ORM, aby mapował tę klasę na tabelę users w bazie danych i mapował atrybuty klasy na kolumny tabeli. Kiedy odpytujesz bazę danych za pomocą ORM-a, nie dostajesz z powrotem surowych wierszy danych. Otrzymujesz w pełni wypełnione danymi instancje swojej klasy User. ORM bezproblemowo obsługuje to tłumaczenie. Co ważniejsze, śledzi stan tych obiektów. Jeśli zmienisz nazwę użytkownika w Pythonie, ORM zauważy, że obiekt został zmodyfikowany. Kiedy powiesz sesji bazy danych, żeby zapisała zmiany, ORM automatycznie dobierze odpowiednie update statements i wykona je przez Core'a. Ty skupiasz się na obiektach Pythona, a ORM ogarnia synchronizację z bazą danych. Najważniejszą rzeczą do zapamiętania jest to, że ORM nie jest black boxem, który zastępuje Core'a. To opcjonalna warstwa zbudowana w całości z komponentów Core'a, pozwalająca na płynne zejście do jawnego generowania SQL-a, kiedy tylko Twoja logika domenowa wymaga maksymalnej wydajności. Jeśli uważasz te odcinki za pomocne i chcesz wesprzeć podcast, wyszukaj DevStoriesEU na Patreonie. Dzięki za spędzenie ze mną tych kilku minut. Do usłyszenia następnym razem, trzymaj się.
2

Engine: Twoja brama do bazy danych

3m 53s

Każda aplikacja SQLAlchemy zaczyna się od Engine. Dowiedz się, jak nawiązać połączenie, czym jest pula połączeń oraz jak dialekty i DBAPI łączą Cię z bazą danych.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 2 z 7. Chcesz komunikować się z bazą danych, ale różne bazy mówią różnymi dialektami, a drivery w Pythonie mają swoje specyficzne dziwactwa. Potrzebujesz jednego, zunifikowanego komponentu, który ogarnie connection pooling, tłumaczenie dialektów i zarządzanie driverami, bez przenikania tych szczegółów do logiki twojej aplikacji. Tym komponentem jest Engine. Engine to punkt wyjścia dla każdej aplikacji w SQLAlchemy. Działa jako centralny rejestr i fabryka połączeń z bazą. Kiedy twoja aplikacja musi skomunikować się z bazą danych, ostatecznie wszystko przechodzi przez Engine. Pod spodem Engine utrzymuje connection pool. Oznacza to, że trzyma cache aktywnych połączeń z bazą, utrzymując je otwarte i gotowe do użycia. Ponowne użycie połączeń z puli jest znacznie szybsze niż negocjowanie zupełnie nowego połączenia sieciowego za każdym razem, gdy musisz wykonać zapytanie. Aby utworzyć instancję obiektu Engine, używasz funkcji create engine. Ta funkcja wymaga URL-a bazy danych. Ten URL to string, który podaje lokalizację bazy danych, dane uwierzytelniające oraz dwa kluczowe elementy konfiguracji: dialekt i DBAPI. Dialekt to rodzina baz danych, w którą celujesz. SQL to standard, ale każdy silnik bazy danych implementuje go nieco inaczej. Dialekt mówi SQLAlchemy, czy formatuje zapytania dla PostgreSQL, MySQL, Oracle, czy SQLite. Obsługuje wszystkie specyficzne dla danego dostawcy różnice, dzięki czemu twój kod w Pythonie pozostaje spójny. Oto kluczowa sprawa. SQLAlchemy nie łączy się z twoją bazą danych bezpośrednio. Zawsze deleguje właściwą komunikację sieciową do zewnętrznego drivera w Pythonie. Ten driver jest znany jako DBAPI. Jeśli używasz PostgreSQL, twoim DBAPI może być psycopg2. Jeśli używasz SQLite, zazwyczaj jest to pysqlite. URL bazy danych określa oba te elementy naraz. Na przykład, URL może zaczynać się od stringa sqlite plus pysqlite. To jawnie mówi obiektowi Engine, aby formatował zapytania używając dialektu SQLite i przesyłał je za pomocą drivera pysqlite. Spójrzmy na konfigurację bazy danych SQLite in-memory. To bardzo popularny wzorzec przy testowaniu, ponieważ baza żyje całkowicie w RAM-ie i znika, gdy program kończy działanie. Wywołujesz funkcję create engine i przekazujesz jej swój string z URL-em. Dla bazy in-memory, ten URL to sqlite plus pysqlite dwukropek ukośnik ukośnik ukośnik dwukropek memory dwukropek. Kiedy odpalasz tę linijkę kodu, obiekt Engine zostaje utworzony, ale nie łączy się od razu z bazą danych. Engine jest leniwy. Przygotowuje konfigurację i ustawia connection pool, ale czeka do momentu, aż po raz pierwszy jawnie poprosisz go o wykonanie zadania, zanim faktycznie uderzy do DBAPI, żeby nawiązać połączenie. Podczas developmentu często musisz dokładnie zweryfikować, co SQLAlchemy wysyła do bazy danych. Funkcja create engine przyjmuje opcjonalny parametr o nazwie echo. Jeśli ustawisz echo na true, Engine będzie logował wszystkie surowe instrukcje SQL, które generuje, bezpośrednio na twoje standardowe wyjście. Działa to jak wbudowane narzędzie do debugowania, pozwalając ci zobaczyć dokładne tłumaczenie między twoimi operacjami w Pythonie a wynikowym kodem SQL. Engine istnieje po to, aby wyabstrahować bałagan związany z połączeniami sieciowymi i driverami baz danych. Daje twojej aplikacji czysty, stabilny interfejs, upewniając się, że reszta twojego kodu nigdy nie musi się martwić o to, jak fizycznie dostać się do bazy. Dzięki za spędzony czas. Mam nadzieję, że dowiedziałeś się czegoś nowego.
3

Mapowanie domeny: Declarative Base i modele

4m 04s

Automatycznie tłumacz swoje klasy Pythona na tabele bazy danych. Omawiamy DeclarativeBase, typy Mapped oraz to, jak mapped_column buduje metadane Twojej bazy danych.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 3 z 7. Piszesz swoje modele domeny w Pythonie, a potem musisz napisać osobny kawałek kodu SQL, tylko po to, żeby utworzyć tabele do ich przechowywania. Z czasem te dwie oddzielne definicje prawie zawsze się rozjeżdżają. Co by było, gdyby twoje klasy w Pythonie mogły automatycznie projektować schemat bazy danych? Właśnie ten problem rozwiązujemy dzisiaj w odcinku Mapping the Domain: Declarative Base and Models. Zanim przyjrzymy się samym klasom, musimy porozmawiać o metadata bazy danych. W SQLAlchemy, metadata to w zasadzie strukturalny katalog. To centralny rejestr w Pythonie, który przechowuje dokładny blueprint twojej bazy danych. Śledzi każdą tabelę, każdą kolumnę i każdy constraint, który zdefiniujesz. Za każdym razem, gdy mapujesz klasę w SQLAlchemy, szczegóły tej klasy trafiają bezpośrednio do tego jednego katalogu. Aby połączyć twoje klasy w Pythonie z tym katalogiem metadata, używasz konstruktu o nazwie DeclarativeBase. Nie używasz DeclarativeBase bezpośrednio. Zamiast tego tworzysz własną, customową klasę bazową, dziedzicząc po niej. Od tego momentu każdy pojedynczy model, który zbudujesz w swojej aplikacji, będzie dziedziczył po twojej customowej klasie bazowej. W momencie, gdy klasa po niej dziedziczy, SQLAlchemy po cichu rejestruje ten nowy model w podległym katalogu metadata. Zastanówmy się, jak tworzysz model User. Definiujesz klasę w Pythonie o nazwie User i dziedziczysz po swojej customowej klasie bazowej. Pierwszą rzeczą, którą definiujesz wewnątrz tej klasy, jest atrybut o nazwie tablename, zapisany z podwójnym podkreśleniem po obu stronach. Ustawiasz go na string user_account. To jawne przypisanie mówi SQLAlchemy dokładnie, która tabela w bazie danych będzie przechowywać te obiekty Pythona. Następnie ustalasz kolumny. SQLAlchemy 2.0 polega w tym celu na standardowych type hintach z Pythona. Definiujesz swoje atrybuty używając specjalnej adnotacji o nazwie Mapped. W przypadku identyfikatora, adnotujesz swój atrybut ID jako Mapped zawierający integer. W przypadku nazwy użytkownika, adnotujesz go jako Mapped zawierający string. Ten type hint jest stricte dla Pythona. Mówi twojemu IDE i twojemu type checkerowi, jakich danych się spodziewać. Ale silnik bazy danych potrzebuje bardziej konkretnych instrukcji niż prosty typ z Pythona. Tutaj do gry wchodzi funkcja o nazwie mapped_column. Przypisujesz mapped_column do atrybutu swojej klasy, a w jej nawiasach konfigurujesz reguły specyficzne dla bazy danych. Dla swojego user ID, wywołujesz mapped_column i przekazujesz flagę, która jawnie oznacza go jako primary key. W przypadku kolumny typu string, możesz przekazać maksymalny limit znaków albo flagę wymagającą, aby pole było unique. Jeśli twój type hint w Pythonie dostarcza cały kontekst, jakiego potrzebuje SQLAlchemy, możesz właściwie całkowicie pominąć mapped_column. SQLAlchemy wywnioskuje podstawową, standardową kolumnę bazy danych bezpośrednio z adnotacji Mapped. Ale w przypadku primary keys, albo jakichkolwiek specyficznych constraintów bazy danych, mapped_column jest absolutnie wymagane. Oto kluczowa sprawa. Kiedy twoje klasy w Pythonie są już napisane, projekt twojego schematu jest już skończony. Katalog metadata zawiera teraz idealną mapę twojej domeny. Możesz wywołać metodę o nazwie create_all na metadata twojej klasy bazowej, przekazując silnik bazy danych. SQLAlchemy patrzy na twoją klasę User, odczytuje zmapowane kolumny, natychmiast tłumaczy je na perfekcyjnie sformatowane instrukcje CREATE TABLE i je wykonuje. Dokładnie ten sam kod w Pythonie, który piszesz, aby uruchomić swoją aplikację, staje się jedynym źródłem prawdy, które buduje strukturę twojej bazy danych. Dzięki za spędzony czas. Mam nadzieję, że dowiedziałeś się czegoś nowego.
4

Układ projektu: Strukturyzacja Twojej aplikacji

3m 31s

Organizacja kodu ma znaczenie. Poznaj najlepsze praktyki strukturyzacji repozytorium projektu SQLAlchemy, aby Twój Engine, modele i sesje pozostały przejrzyste i łatwe w utrzymaniu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 4 z 7. Napisałeś już swoje modele, engine i queries. Ale wrzucenie ich wszystkich do jednego pliku to prosta droga do koszmaru w utrzymaniu i circular imports. Rozwiązaniem jest Project Layout, czyli strukturyzacja twojej aplikacji. Kiedy przeglądasz tutoriale, kod zazwyczaj znajduje się w jednym skrypcie. Widzisz setup engine'u, base class, modele i queries ułożone z góry na dół. Taki design świetnie nadaje się do nauki składni, ale jeśli spróbujesz zbudować w ten sposób system na produkcję, wszystko się rozpadnie. Gdy tylko dodasz web routes albo background workers, zaczną się problemy. Jeśli twój web route musi zaimportować model usera, ale ten model znajduje się w tym samym pliku, który startuje serwer aplikacji albo inicjalizuje połączenie z bazą danych, Python się gubi. W rezultacie dostajesz circular imports, a twój kod staje się niemożliwy do przetestowania. Potrzebujesz ścisłego separation of concerns. Standardowy pattern to podzielenie tego jednego skryptu na oddzielne moduły w zależności od ich zadania. Najpierw tworzysz dedykowany plik, zazwyczaj nazywany database dot py. Ten plik ma dokładnie jedną odpowiedzialność, którą jest zarządzanie połączeniem z bazą danych. To tutaj umieszczasz wywołanie create engine i robisz setup swojego session maker'a. Nie definiujesz tutaj tabel i nie odpalasz tu queries. Izolując engine, masz pewność, że twoja aplikacja utworzy tylko jeden connection pool. Każdy inny moduł w twoim projekcie może bezpiecznie zaimportować session maker z tego pliku, bez przypadkowego odpalania logiki startowej aplikacji. Następnie przenosisz definicje tabel do pliku o nazwie models dot py. Ten plik zawiera twój Declarative Base i wszystkie twoje mapped classes, takie jak obiekt User czy Address. Nie importuje on niczego z twojego pliku database. To jest kluczowa sprawa. Twoje modele definiują kształt danych, ale nie wiedzą, jak połączyć się z bazą. Ponieważ models dot py nie ma żadnych zależności od engine'u ani aktywnej sesji, możesz importować swoje mapped classes w dowolnym miejscu aplikacji bez obaw o side effects. Jeśli twój projekt mocno urośnie, możesz nawet podzielić modele na katalog z osobnymi plikami dla różnych domen. Dopóki wszystkie importują dokładnie tę samą instancję Declarative Base, SQLAlchemy wie, że należą do tej samej kolekcji metadanych. Na koniec potrzebujesz miejsca do faktycznego wykonywania twoich queries. Wykonywanie queries trzymasz całkowicie oddzielnie od swoich modeli i plików połączeniowych. Zazwyczaj trafia to do twoich route handlers albo dedykowanych service files. Gdy aplikacja potrzebuje danych, service file importuje session maker z modułu database oraz wymagane mapped classes z modułu modeli. Otwiera sesję używając context managera, odpala select statement, pobiera obiekty i pozwala, aby context manager bezpiecznie zamknął połączenie po zakończeniu bloku. Service file pełni rolę koordynatora. Strukturyzacja projektu w ten sposób sprawia, że twoja logika połączeń jest odizolowana, schematy danych przenośne, a operacje biznesowe przejrzyste. Najważniejsza zasada, o której musisz pamiętać, to to, że twoje modele danych nigdy nie powinny importować database engine'u. To wszystko w tym odcinku. Dzięki za wysłuchanie i keep building!
5

Session: Opanowanie Unit of Work

3m 55s

Odkryj wzorzec Unit of Work poprzez Session w ORM. Dowiedz się, jak dodawać obiekty, kiedy występują operacje flush i jak perfekcyjnie wykonywać commit transakcji.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 5 z 7. Wyobraź sobie przestrzeń roboczą, w której możesz zakolejkować dziesiątki zmian w bazie danych i wypchnąć je wszystkie idealnie naraz, albo natychmiast anulować. To dokładnie ten problem, który rozwiązuje koncepcja z tego odcinka: Session, czyli opanowanie wzorca Unit of Work. Session w SQLAlchemy to główny sposób, w jaki twoje obiekty w Pythonie komunikują się z bazą danych. Działa w oparciu o wzorzec zwany Unit of Work. Kiedy używasz Session, nie odpalasz pojedynczych komend bezpośrednio do bazy danych. Wchodzisz w interakcję z inteligentną przestrzenią roboczą. Session monitoruje twoje operacje, zbiera dodania, modyfikacje i usunięcia, a następnie oblicza najwydajniejszy sposób na przetłumaczenie ich na SQL w odpowiednim momencie. Wewnątrz tej przestrzeni znajduje się mechanizm o nazwie Identity Map. To wewnętrzny słownik, który łączy primary key wiersza w bazie danych z konkretnym adresem w pamięci twojego obiektu w Pythonie. Jeśli poprosisz o użytkownika z ID równym pięć, Session najpierw sprawdzi Identity Map. Jeśli obiekt jest już załadowany, dostaniesz z powrotem dokładnie tę samą instancję w Pythonie. To gwarantuje, że nigdy nie będziesz mieć dwóch różnych obiektów w Pythonie reprezentujących ten sam wiersz w bazie danych w tym samym czasie. Spójrzmy na dodawanie nowych danych. Zaczynasz od utworzenia instancji zmapowanej klasy User, nadając jej imię, na przykład Alice. Na tym etapie twój obiekt jest w stanie zwanym transient. Istnieje wyłącznie w pamięci Pythona. Baza danych nie ma pojęcia o jego istnieniu, a Session nic o nim nie wie. Aby powiązać obiekt z twoją przestrzenią roboczą, przekazujesz go do metody add w Session. Obiekt przechodzi w stan zwany pending. Session zarejestrowała twoją chęć dodania tego nowego użytkownika, ale nie wysłała jeszcze żadnego zapytania SQL przez sieć. Obiekt po prostu czeka w kolejce. To wprowadza wyraźną różnicę między flush a commit. Kiedy wywołujesz flush na Session, bierze ona twoją kolejkę pending i wypycha zmiany do obecnej transakcji w bazie danych. Emituje instrukcję SQL INSERT. Baza danych ją wykonuje i przypisuje primary key. Z powrotem w twoim kodzie w Pythonie, twój obiekt użytkownika jest natychmiast uzupełniany o to nowe ID z bazy danych. Obiekt przeszedł w stan persistent. Oto kluczowa sprawa. Mimo że obiekt jest w stanie persistent i ma swoje ID, zmiana wciąż nie jest permanentna. Baza danych izoluje tę transakcję. Załóżmy, że twój kod nagle wyłapie błąd, na przykład nieprawidłowy adres e-mail użytkownika, dla którego właśnie wywołałeś flush. Ponieważ nie wykonałeś commit, możesz wywołać rollback. Baza danych całkowicie odrzuca transakcję i nic nie zostaje zapisane w rzeczywistych tabelach. Kiedy masz absolutną pewność, że dane są poprawne, wywołujesz commit. Commit finalizuje transakcję i zapisuje dane na dysku. Wywołanie commit automatycznie uruchamia najpierw flush, więc zazwyczaj nie musisz wywoływać flush ręcznie, chyba że konkretnie potrzebujesz odczytać wygenerowany primary key przed ukończeniem reszty swojej logiki. Session działa jak bufor między pamięcią twojej aplikacji a trwałym magazynem danych, pozwalając ci na bezpieczne zarządzanie złożonymi zmianami danych, zanim wprowadzisz je w życie. Dzięki za wysłuchanie. Trzymajcie się wszyscy.
6

Pobieranie danych: Nowoczesna konstrukcja Select

3m 05s

Pobieraj dane dokładnie tak, jak tego potrzebujesz. Odkrywamy ujednoliconą konstrukcję select() w SQLAlchemy 2.0, filtrowanie za pomocą where() oraz wykonywanie zapytań przy użyciu Session.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 6 z 7. W starszych wersjach SQLAlchemy pisanie zapytań przypominało pracę z rozdwojonym mózgiem. Musiałeś zapamiętać jedną składnię dla operacji Core i zupełnie inny zestaw reguł dla ORM. Za każdym razem, gdy pisałeś zapytanie, musiałeś się zatrzymać i zadać sobie pytanie, czy pobierasz surowe wiersze, czy zmapowane obiekty. Wersja 2.0 zatarła tę granicę dzięki nowoczesnej konstrukcji Select. Koncepcja jest prosta. Mamy teraz jedną, ujednoliconą funkcję o nazwie select. Przekazujesz do niej bezpośrednio encję, którą chcesz odpytać. Jeśli masz klasę ORM o nazwie User, przekazujesz klasę User do funkcji select. Tworzy to obiekt select reprezentujący zapytanie do powiązanej tabeli user. Ten obiekt select jest generatywny. Wywołanie funkcji select nie wykonuje jeszcze niczego na bazie danych. Zamiast tego tworzy obiekt expression w pamięci. Kiedy wywołujesz metodę na tym obiekcie, aby dodać warunki, zwraca on świeży obiekt select z zastosowanymi nowymi warunkami. Pozwala ci to na dynamiczne budowanie złożonych zapytań, krok po kroku, przekazując ten obiekt wewnątrz aplikacji, zanim w ogóle skomunikujesz się z bazą danych. To tyle, jeśli chodzi o bazowe zapytanie. Jak je filtrować? Dołączasz metodę where do swojego obiektu select. Wewnątrz metody where używasz standardowych operatorów Pythona bezpośrednio na atrybutach zmapowanej klasy. Na przykład, aby znaleźć konkretnego użytkownika, wpisujesz klasę User, kropkę, name, a następnie dwa znaki równości i docelowy string. SQLAlchemy to przechwytuje. Przeciąża standardowe operatory Pythona, takie jak podwójny znak równości czy znak większości. Zamiast ewaluować to wyrażenie do true lub false w Pythonie, tłumaczy je na poprawną składnię SQL dla klauzuli WHERE w bazie danych. Masz teraz w pełni skonstruowany obiekt query. Aby faktycznie pobrać swoje dane, przekazujesz ten obiekt do sesji. Możesz przekazać go do standardowej metody execute na sesji, ale to zwróci obiekt result, w którym każdy wiersz jest w zasadzie tuplą. Nawet jeśli odpytałeś pojedynczą klasę ORM, twój zmapowany obiekt jest uwięziony w jednoelementowej tupli i musisz go ręcznie wyciągnąć po zwróceniu wyników. I tu jest kluczowa sprawa. Kiedy chcesz odzyskać obiekty ORM, użyj zamiast tego metody scalars na sesji. Przekazujesz swój obiekt select do session kropka scalars. Sesja uruchamia query, automatycznie rozpakowuje te tuple z result setu pod spodem i zwraca iterable twoich w pełni wypełnionych obiektów ORM. Natychmiast otrzymujesz czystą kolekcję instancji User, gotową do modyfikacji lub odczytu. Ujednolicona konstrukcja select oznacza, że dokładnie te same bloki budujące query, których używasz dla obiektów ORM, mogą być wykonywane bezpośrednio na niskopoziomowych połączeniach Core, zostawiając ci dokładnie jeden model mentalny do utrzymania w całej warstwie bazy danych. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
7

Łączenie elementów: Relacje i JOINy

3m 51s

Płynnie łącz swoje tabele. Dowiedz się, jak konfigurować relacje, używać back_populates i automatycznie zarządzać SQL JOINs w powiązanych modelach.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. SQLAlchemy, odcinek 7 z 7. Relacyjne bazy danych istnieją, ponieważ dane się łączą, ale ręczne pisanie skomplikowanych joinów za każdym razem, gdy potrzebujesz powiązanego rekordu, szybko staje się męczące. Kończysz z powtarzalną logiką query rozsianą po całej aplikacji. Connecting the Dots: Relationships and Joins rozwiązuje ten problem, pozwalając, żeby object-relational mapper ogarniał te połączenia za ciebie. Na poziomie bazy danych tabele łączą się za pomocą foreign keys. Jeśli użytkownik ma wiele adresów, tabela adresów ma kolumnę przechowującą user ID. To standardowa relacja one-to-many. Ale kiedy piszesz kod w Pythonie, nie chcesz wyciągać ID i pisać drugiego query, tylko po to, żeby znaleźć te adresy. Chcesz odwołać się do property na swoim obiekcie user i natychmiast zobaczyć listę obiektów address. Właśnie to zapewnia konstrukcja relationship. Wypełnia ona lukę między foreign keys w bazie danych a atrybutami obiektów w Pythonie. Żeby to skonfigurować, potrzebujesz dwóch rzeczy. Po pierwsze, deklarujesz foreign key po stronie bazy danych. W swoim modelu Address definiujesz kolumnę o nazwie user ID i jawnie oznaczasz ją jako foreign key wskazujący na tabelę User. Po drugie, definiujesz relationship po stronie Pythona. W modelu User definiujesz property o nazwie addresses, używając funkcji relationship, wskazującej na model Address. Definiujesz również property relationship w modelu Address, wskazujące z powrotem na model User. Oto kluczowa sprawa. SQLAlchemy musi wiedzieć, że te dwa property reprezentują dwie strony dokładnie tego samego połączenia. Mówisz mu o tym, używając parametru back populates w obu definicjach relationship. W modelu User, relationship addresses ustawia back populates na string z nazwą property user. W modelu Address, relationship user ustawia back populates na string z nazwą property addresses. Dzięki back populates, ORM utrzymuje twoje obiekty w Pythonie zsynchronizowane w pamięci. Jeśli weźmiesz obiekt address i przypiszesz go do usera, ten adres natychmiast pojawi się na liście addresses tego usera. Framework zajmuje się śledzeniem powiązań, zanim w ogóle zrobisz commit do bazy danych. Kiedy twoje obiekty są już połączone, wykonujesz na nich query. Załóżmy, że wykonujesz instrukcję select, żeby znaleźć usera o imieniu Alice. Baza danych zwraca wiersz usera, a ty dostajesz obiekt. Dokładnie w tym momencie, adresy Alice nie są załadowane. ORM ich nie pobiera, bo jeszcze o nie nie prosiłeś. Kiedy w końcu odwołujesz się do property addresses w swoim kodzie, na przykład żeby przeiterować po nazwach ulic, ORM zauważa, że brakuje danych. Automatycznie wstrzymuje twój program, wysyła drugą instrukcję select do bazy danych, żeby znaleźć wszystkie adresy z ID Alice, i wypełnia listę. To nazywa się lazy loading. To domyślne zachowanie, ponieważ zapobiega zaciąganiu przez aplikację tysięcy powiązanych wierszy do pamięci, chyba że są absolutnie wymagane. Robisz query o usera, odwołujesz się do jego properties, a system płynnie nawiguje po foreign keys i wysyła niezbędne queries w tle. Prawdziwą siłą konstrukcji relationship jest to, że ukrywa mechaniczną złożoność joinów, pozwalając ci nawigować po całej bazie danych po prostu poprzez interakcję z połączonymi obiektami w Pythonie. Żeby opanować te koncepcje, przejrzyj oficjalną dokumentację i spróbuj samodzielnie skonfigurować własne modele w praktyce. Śmiało odwiedź devstories dot eu, żeby zasugerować tematy, które chcesz, żebyśmy poruszyli w przyszłych seriach. To wszystko w tym odcinku. Dzięki za wysłuchanie i koduj dalej!