SQLAlchemy
SQLAlchemy SQL Toolkit i ORM to zestaw narzędzi do pracy z bazami danych.
SQLAlchemy
SQLAlchemy
SQLAlchemy Core skupia się na schemacie bazy danych, zaś SQLAlchemy ORM na modelu
relacyjnej bazy danych, który odwzorowuje ten schemat.
SQLAlchemy
Wpiera te bazy przez pakiety:
Postgres: psycopg2 SQLite: pysqlite MySQL: MySQLDB
Oracle: cx_Oracle
MS-SQL: adodbapi pymssql Firebird: kinterbasdb
Instalacja
sudo aptget install postgresql
sudo aptget install pythonsqlalchemy sudu aptget install pythonmigrate
sudo aptget install pythonpsycopg2 sudo aptget install pgadmin3
xhost +local:
# sudo passwd postgres
# new password: postgres
# re: postgres sudo su postgres
createuser P dbstep createdb dbstepy
pgadmin3
Nowe połączenie: dbstepy | localhost | 5432 | postgres | dbstep | dbstep
Instalacja
Sprawdzenie instalacji:
Sprawdzenie instalacji:
import sqlalchemy import sqlalchemy
sqlalchemy.__version__
sqlalchemy.__version__
Połączenie
Najpierw należy stworzyć silnik Najpierw należy stworzyć silnik::
from sqlalchemy import * from sqlalchemy import *
sqlalchemy.create_engine(*args, sqlalchemy.create_engine(*args,
**kwargs)
**kwargs)
Łańcuch dostępu do bazy (
Łańcuch dostępu do bazy (argsargs):):
dialect+driver://user:password@ho dialect+driver://user:password@ho
st/dbname[?key=value..]
st/dbname[?key=value..]
dialect to np.
dialect to np.
mysql, oracle, postgresql mysql, oracle, postgresql
driver nazwa DBAPI:
driver nazwa DBAPI:
psycopg2, pyodbc, cx_oracle
psycopg2, pyodbc, cx_oracle, itd., itd.
Połączenie
Dla postgresa Dla postgresa::
# default
# default engine = engine =
create_engine(’postgresql://scott create_engine(’postgresql://scott
:tiger@localhost/mydatabase’) :tiger@localhost/mydatabase’)
# psycopg2
# psycopg2 engine = engine =
create_engine(’postgresql+psycopg create_engine(’postgresql+psycopg 2://scott:tiger@localhost/mydatab 2://scott:tiger@localhost/mydatab
ase’) ase’)
Połączenie
Dla postgresa Dla postgresa::
# pg8000
# pg8000 engine = engine =
create_engine(’postgresql+pg8000:
create_engine(’postgresql+pg8000:
//scott:tiger@localhost/mydatabas //scott:tiger@localhost/mydatabas e’)e’)
# Jython
# Jython engine = engine =
create_engine(’postgresql+zxjdbc:
create_engine(’postgresql+zxjdbc:
//scott:tiger@localhost/mydatabas //scott:tiger@localhost/mydatabas e’)e’)
Połączenie
kwargs odpowiada za specyficzne parametry odpowiada za specyficzne parametry dla dialektu, bazy danych, itp.
dla dialektu, bazy danych, itp.:: echo=False –
echo=False – logowanie poleceń na stdout logowanie poleceń na stdout encoding='utf8' –
encoding='utf8' – domyślne kodowanie domyślne kodowanie znaków, łańcuchy tak kodowane wyświetlane znaków, łańcuchy tak kodowane wyświetlane
są jako
są jako u'łańcuch' u'łańcuch'
convert_unicode=False –
convert_unicode=False – domyślne domyślne konwertowanie łańcuchów z bazie na unicode konwertowanie łańcuchów z bazie na unicode
execution_options –
execution_options – w tym m.in. w tym m.in.
autocommit autocommit
Połączenie
kwargs odpowiada za specyficzne parametry odpowiada za specyficzne parametry dla dialektu, bazy danych, itp.
dla dialektu, bazy danych, itp.:: listeners –
listeners – listenery na zdarzenia listenery na zdarzenia związane z pulą połączeń
związane z pulą połączeń
Dostępnych jest wiele innych parametrów.
Dostępnych jest wiele innych parametrów.
Przykład Przykład
pg_db = pg_db =
create_engine('postgres://dbstep:
create_engine('postgres://dbstep:
dbstep@localhost:5433/dbstepy') dbstep@localhost:5433/dbstepy')
Najczęściej domyślny port to
Najczęściej domyślny port to 54325432..
Połączenie
pg_db jest to teraz jest to teraz EngineEngine. Posiada on wiele . Posiada on wiele metod
metod::
begin –
begin – zwracająca kontekstzwracająca kontekst connect –
connect – zwracająca połączeniezwracająca połączenie execute –
execute – wykonująca poleceniewykonująca polecenie table_names –
table_names – zwracająca dostępne tabele zwracająca dostępne tabele w bazie
w bazie
transaction –
transaction – opakowująca funkcję w opakowująca funkcję w transakcję
transakcję
Przestarzałe
Przestarzałe create, drop create, drop (teraz należy używać (teraz należy używać Table.create(), Index.drop(),
MetaData.create_all()))
Połączenie
Sprawdźmy działanie połączenia:
Sprawdźmy działanie połączenia:
Przykład Przykład
print pg_db.execute("select print pg_db.execute("select
1").scalar() 1").scalar()
Bez połączenia select nie wykonałby się.
Bez połączenia select nie wykonałby się.
MetaData
Tabela z informacją o tabelach. Klasę Tabela z informacją o tabelach. Klasę
powiązaną z nią przez użytkownika nazywamy powiązaną z nią przez użytkownika nazywamy
Mapperem.
Mapperem.
Zatem klasyczne powiązanie wygląda tak:
Zatem klasyczne powiązanie wygląda tak:
MetaData – obiekt a na MetaData – klasa A MetaData – obiekt a na MetaData – klasa A
pythona + mapper(A,a).
pythona + mapper(A,a).
Mapowanie
Mając połączenie z bazą danych możemy Mając połączenie z bazą danych możemy
przystąpić do mapowania bazy danych na klasy.
przystąpić do mapowania bazy danych na klasy.
Aby do tego przystąpić musimy mieć bazę Aby do tego przystąpić musimy mieć bazę
deklaratywną.
deklaratywną.
Przykład Przykład
from sqlalchemy.ext.declarative from sqlalchemy.ext.declarative
import declarative_base import declarative_base
Baza = declarative_base() Baza = declarative_base()
Po niej będziemy nasze klasy dziedziczyć.
Po niej będziemy nasze klasy dziedziczyć.
Mapowanie
Można ją parametryzować, np.
Można ją parametryzować, np.
metadata
metadata – powoduje współdzielenie MetaData – powoduje współdzielenie MetaData z innymi bazami
z innymi bazami
Ma też atrybuty i metody, np.:
Ma też atrybuty i metody, np.:
__tablename__
__tablename__ - nazwa tabeli- nazwa tabeli __init__
__init__ - konstruktor, metoda no-op- konstruktor, metoda no-op __repr__
__repr__ - jaka ma być odpowiedź na żądanie - jaka ma być odpowiedź na żądanie wyświetlenia obiektu
wyświetlenia obiektu
Stwórzmy kilka typowych klas.
Stwórzmy kilka typowych klas.
Przykład Przykład
from sqlalchemy import * from sqlalchemy import *
# Column, Integer, String
# Column, Integer, String
Tworzenie klas
Przykład Przykład
class Uzytkownik(Baza):
class Uzytkownik(Baza):
__tablename__ = 'uzytkownicy' __tablename__ = 'uzytkownicy' id = Column(Integer, id = Column(Integer,
primary_key = True) primary_key = True)
imie = Column(String(50))imie = Column(String(50)) nazwisko = nazwisko =
Column(String(100)) Column(String(100))
haslo = Column(String(100))haslo = Column(String(100))
zalogowany = Column(Boolean, zalogowany = Column(Boolean, default=False)
default=False)
Tworzenie klas
#opcjonalne
#opcjonalne
def __init__(self, imie, def __init__(self, imie, nazwisko, haslo):
nazwisko, haslo):
self.imie = imieself.imie = imie
self.nazwisko = nazwiskoself.nazwisko = nazwisko
self.haslo = haslo self.haslo = haslo def __repr__(self):def __repr__(self):
return return
"<Uzytkownik('%s','%s','%s','%s')
"<Uzytkownik('%s','%s','%s','%s')
>" % (self.imie, self.nazwisko,
>" % (self.imie, self.nazwisko, self.haslo, self.zalogowany)
self.haslo, self.zalogowany) def zaloguj_sie(self):def zaloguj_sie(self):
self.zalogowany=Trueself.zalogowany=True
Tworzenie klas
Metody, jakie można przedeklarować lub używać:
Metody, jakie można przedeklarować lub używać:
append_column
append_column – dodaje kolumnę, ale tylko do – dodaje kolumnę, ale tylko do klasy – nie zmienia schematu bazy
klasy – nie zmienia schematu bazy create
create – tworzy – tworzy dropdrop – usuwa – usuwa
exists
exists – sprawdza istnienie – sprawdza istnienie itd.itd.
Tworzenie klas
Podobnie przy tworzeniu tej klasy możemy Podobnie przy tworzeniu tej klasy możemy
parametryzować jej użycie:
parametryzować jej użycie:
namename – inna nazwa tabeli w bazie – inna nazwa tabeli w bazie
Są również parametry związane z automatycznym Są również parametry związane z automatycznym
wczytywaniem wartości z bazy, czy listenery.
wczytywaniem wartości z bazy, czy listenery.
Tworzenie tabel
Po stworzeniu modelu bazy danych, możemy Po stworzeniu modelu bazy danych, możemy
utworzyć na jej podstawie schemat.
utworzyć na jej podstawie schemat.
Przykład Przykład
Baza.metadata.create_all(pg_db) Baza.metadata.create_all(pg_db)
Sprawdźmy, jak wygląda:
Sprawdźmy, jak wygląda:
pgadmin3 pgadmin3
Tworzenie instancji
Przykład Przykład
zwirek = Uzytkownik('Antoni', zwirek = Uzytkownik('Antoni',
'Zwirek', 'zwirek123') 'Zwirek', 'zwirek123')
muchomorek = Uzytkownik('Albert', muchomorek = Uzytkownik('Albert',
'Muchomorek', 'mucha123') 'Muchomorek', 'mucha123')
wodnik = Uzytkownik(imie = wodnik = Uzytkownik(imie =
'Wodnik', nazwisko='Szuwarek', 'Wodnik', nazwisko='Szuwarek',
haslo='bulbul123') haslo='bulbul123')
print zwirek print zwirek
print muchomorek print muchomorek
print wodnik print wodnik
print str(muchomorek.id) print str(muchomorek.id)
Sesja
Ostatnie polecenie pokazuje, że id jest None.
Ostatnie polecenie pokazuje, że id jest None.
Oznacza to tyle, że jeszcze nie zostało zapisane w Oznacza to tyle, że jeszcze nie zostało zapisane w bazie – sekwencja, która powstaje dla primary key bazie – sekwencja, która powstaje dla primary key
w postgresie, nie została jeszcze wykonana dla w postgresie, nie została jeszcze wykonana dla
tego obiektu.
tego obiektu.
Możemy przesłać obiekt do bazy (jako wiersz) Możemy przesłać obiekt do bazy (jako wiersz)
dopiero w sesji.
dopiero w sesji.
Sesja
Przykład Przykład
Sesja = sessionmaker(bind = Sesja = sessionmaker(bind =
pg_db) pg_db)
#Sesja = sessionmaker()
#Sesja = sessionmaker()
#Sesja.configure(bind = pg_db)
#Sesja.configure(bind = pg_db) sesja = Sesja()
sesja = Sesja() sesja
sesja typu typu SessionSession zapamiętuje szczegóły zapamiętuje szczegóły połączenia z klientem.
połączenia z klientem.
sessionmaker
sessionmaker tworzy obiekt, która pozwala na tworzy obiekt, która pozwala na pobranie/stworzenie instancji klasy Session w pobranie/stworzenie instancji klasy Session w
dowolnym miejscu.
dowolnym miejscu.
Sesja
W sesji znajdują się unikalni reprezentanci W sesji znajdują się unikalni reprezentanci
obiektów z bazy danych (strukura
obiektów z bazy danych (strukura IdentityMapIdentityMap), a ), a wszystkie zmiany są „wstrzymywane”, aż do
wszystkie zmiany są „wstrzymywane”, aż do momentu zatwierdzenia. Po zatwierdzeniu momentu zatwierdzenia. Po zatwierdzeniu
IdentityMap
IdentityMap jest wypełniana na nowo. jest wypełniana na nowo.
Sesja
Niektóre z dostępnych parametrów sesionmaker:
Niektóre z dostępnych parametrów sesionmaker:
autoflush
autoflush – natychmiastowe zmiany (ale nie – natychmiastowe zmiany (ale nie zatwierdzone), bez oczekiwania na taką
zatwierdzone), bez oczekiwania na taką
konieczność (np. mimo braku odczytu z bazy) – konieczność (np. mimo braku odczytu z bazy) –
na końcu wystarczy
na końcu wystarczy commit()commit() zatwierdzający zatwierdzający autocommit
autocommit – natychmiastowe zatwierdzanie – natychmiastowe zatwierdzanie zmian w odrębnych chwilowych transakcjach
zmian w odrębnych chwilowych transakcjach expire_on_commit
expire_on_commit – wygasza sesję po – wygasza sesję po zatwierdzeniu zmian – domyślne,
zatwierdzeniu zmian – domyślne,
bindbind – powiązanie sesji z konkretnym – powiązanie sesji z konkretnym połączeniem
połączeniem
Sesja
Niektóre z metod
Niektóre z metod SessionSession::
add add - dodaje obiekt do sesji- dodaje obiekt do sesji add_all
add_all - dodaje kolekcję obiektów do sesji- dodaje kolekcję obiektów do sesji begin
begin – początek transakcji – początek transakcji begin_nested
begin_nested – początek transakcji – początek transakcji zagnieżdżonej
zagnieżdżonej commit
commit – zatwierdzenie zmian – zatwierdzenie zmian dirty
dirty – obiekty zmienione – obiekty zmienione newnew – obiekty nowe – obiekty nowe
Sesja
execute
execute - wykonanie polecenia - wykonanie polecenia flush
flush - zapis zmian, ale jeszcze nie - zapis zmian, ale jeszcze nie zatwierdzony
zatwierdzony query
query – zapytanie – zapytanie rollback
rollback – wycofanie się z zapisanych zmian – wycofanie się z zapisanych zmian scalar
scalar – jak – jak executeexecute, ale z liczbą w wyniku, ale z liczbą w wyniku
Transakcja
Jednostka kontaktu z bazą.
Jednostka kontaktu z bazą.
Stany obiektów
- - transienttransient - instancja nie znajduje się w sesji i nie - instancja nie znajduje się w sesji i nie jest zapisana w bazie, jedyne powiązanie to takie, jest zapisana w bazie, jedyne powiązanie to takie,
że klasa ma powiązany
że klasa ma powiązany mapper()mapper()
- - pendingpending - po - po add()add(), jest w sesji, ale nie jest , jest w sesji, ale nie jest zapisana w bazie aż do
zapisana w bazie aż do flush()flush()
- - persistentpersistent - instancja jest w sesji i w bazie - instancja jest w sesji i w bazie
- - detacheddetached - jest w bazie, ale nie ma jej w żadnej - jest w bazie, ale nie ma jej w żadnej sesji. To normalny stan, z tym wyjątkiem, że nie sesji. To normalny stan, z tym wyjątkiem, że nie
ma możliwości wykonania żadnego SQLa w celu ma możliwości wykonania żadnego SQLa w celu
pobrania kolekcji lub atrybutów, które nie są już pobrania kolekcji lub atrybutów, które nie są już
załadowane lub ustawione na ``
załadowane lub ustawione na ``expiredexpired''.''.
Tworzenie obiektów
Na bazie naszego przykładu, po
Na bazie naszego przykładu, po add()add() mamy mamy obiekty „w sesji”. Wszystkie są „
obiekty „w sesji”. Wszystkie są „pendingpending”, ale ”, ale jeszcze nie „
jeszcze nie „persistedpersisted”.”.
Przykład Przykład
zwirek_persisted = zwirek_persisted =
sesja.query(Uzytkownik).filter_by sesja.query(Uzytkownik).filter_by
(nazwisko='Zwirek').first() (nazwisko='Zwirek').first()
print str(zwirek.id) print str(zwirek.id)
print str(zwirek_persisted.id) print str(zwirek_persisted.id)
Teraz już zmiany zostały zatwierdzone w bazie – Teraz już zmiany zostały zatwierdzone w bazie –
mają id. Można to zrobić również przez
mają id. Można to zrobić również przez flush()flush()..
Rollback
print print
sesja.query(Uzytkownik).count() sesja.query(Uzytkownik).count()
Wycofujemy zmiany:
Wycofujemy zmiany:
print sesja.rollback() print sesja.rollback()
print print
sesja.query(Uzytkownik).count() sesja.query(Uzytkownik).count()
Zapytania
sesja.add_all([Uzytkownik('Dzoana sesja.add_all([Uzytkownik('Dzoana
','Krupa','tapmadl'), ','Krupa','tapmadl'),
Uzytkownik('Shakira','Ripoll',Non Uzytkownik('Shakira','Ripoll',Non e), e),
Uzytkownik('Grzegorz','Markowski' Uzytkownik('Grzegorz','Markowski'
, 'perfect123')]) , 'perfect123')])
print print
sesja.query(Uzytkownik).filter_by sesja.query(Uzytkownik).filter_by (nazwisko='Markowski').first().id (nazwisko='Markowski').first().id
Zapytania -filtrowanie
query()
query() zwraca obiekt zwraca obiekt QueryQuery. Metody:. Metody:
add_column, add_columns
add_column, add_columns - dodaje - dodaje kolumnę do wynikowych kolumn
kolumnę do wynikowych kolumn
allall - zwraca listę obiektów tej klasy- zwraca listę obiektów tej klasy as_scalar
as_scalar - zmiana pełnego selekta na - zmiana pełnego selekta na
podselekta zwracającego jedną wartość liczbową podselekta zwracającego jedną wartość liczbową
autoflush
autoflush - dla tego zapytania można - dla tego zapytania można wstrzymać
wstrzymać flushflush
column_description
column_description - wynik razem z - wynik razem z opisem kolumn
opisem kolumn count
count - zlicza liczbę wierszy - zlicza liczbę wierszy
Zapytania -filtrowanie
distinct
distinct - metoda ukrywająca powtarzające - metoda ukrywająca powtarzające się (pod jakimś względem) wiersze
się (pod jakimś względem) wiersze delete
delete - usuwa wyszukane wiersze z - usuwa wyszukane wiersze z bazy/modelu, zwraca liczbę usuniętych, z bazy/modelu, zwraca liczbę usuniętych, z
pominięciem kaskad pominięciem kaskad
except_
except_ ii except_all except_all - pozwala odsiać - pozwala odsiać część wyników poprzez podzapytanie
część wyników poprzez podzapytanie filter
filter - filtruje po warunku dla dokładnie - filtruje po warunku dla dokładnie określonego pola
określonego pola filter_by
filter_by – filtrowanie po wskazanym kluczu – filtrowanie po wskazanym kluczu
Zapytania -filtrowanie
first
first - zwraca pierwszy obiekt wśród - zwraca pierwszy obiekt wśród pasujących do wyszukiwania
pasujących do wyszukiwania from_statement
from_statement – wykonuje podane – wykonuje podane zapytanie
zapytanie
getget – zwraca obiekt o podanym primary key – zwraca obiekt o podanym primary key group_by, having
group_by, having – elementy SQL, zgodnie – elementy SQL, zgodnie ze standardem
ze standardem
oneone - zwraca jeden obiekt pasujący, jeśli jest ich - zwraca jeden obiekt pasujący, jeśli jest ich więcej lub nie ma żadnego - zwraca błąd
więcej lub nie ma żadnego - zwraca błąd MultipleResultsFound
MultipleResultsFound lub lub NoResultFoundNoResultFound
Zapytania -filtrowanie
union, union_all
union, union_all - pozwala dołączyć - pozwala dołączyć nowe lub dodatkowe z drugiego zapytania
nowe lub dodatkowe z drugiego zapytania intersect, intersect_all
intersect, intersect_all – przecięcie – przecięcie joinjoin – złączenie, razem z filter – złączenie, razem z filter
label
label – zmiana nagłówka kolumny– zmiana nagłówka kolumny limit
limit – ogranicza liczbę wyników – ogranicza liczbę wyników order_by
order_by – porządkuje – porządkuje outerjoin
outerjoin – złączenie lewostronne – złączenie lewostronne statement
statement – polecenie sql, które reprezentuje – polecenie sql, które reprezentuje to Query
to Query update
update – zmienia wartości – zmienia wartości
Relacje
Związki między tabelami poprzez klucze obce Związki między tabelami poprzez klucze obce
mogą mieć postać
mogą mieć postać jeden-do-wielujeden-do-wielu, , wiele-do-wiele-do- jednego
jednego, , jeden-do-jednegojeden-do-jednego i i wiele-do-wieluwiele-do-wielu
(realizacja poprzez odrębną tabelę i dwie relacje:
(realizacja poprzez odrębną tabelę i dwie relacje:
jeden-do wielu
jeden-do wielu i i wiele-do-jednegowiele-do-jednego))
Relacje: jeden-do-wielu
Klucz obcy jest w klasie „wiele”.
Klucz obcy jest w klasie „wiele”.
Przykład Przykład
from sqlalchemy import ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref from sqlalchemy.orm import relationship, backref
class Kategorie(Baza):
class Kategorie(Baza):
__tablename__ = 'kategorie'__tablename__ = 'kategorie'
id = Column(Integer,primary_key = True)id = Column(Integer,primary_key = True) czasopisma = relationship("Czasopisma")czasopisma = relationship("Czasopisma") nazwa = Column(String(100))nazwa = Column(String(100))
def __init__ (self, nazwa):def __init__ (self, nazwa):
self.nazwa = nazwaself.nazwa = nazwa
Relacje: jeden-do-wielu
class Czasopisma(Baza):
class Czasopisma(Baza):
__tablename__ = 'czasopisma'__tablename__ = 'czasopisma'
id = Column(Integer,primary_key = True)id = Column(Integer,primary_key = True) nazwa = Column(String(100))nazwa = Column(String(100))
id_kat = id_kat =
Column(Integer,ForeignKey("kategorie.id")) Column(Integer,ForeignKey("kategorie.id")) kategoria = relationship("Kategorie", kategoria = relationship("Kategorie",
backref=backref('czasopisma',order_by=id)) backref=backref('czasopisma',order_by=id)) def __init__ (self, nazwa):def __init__ (self, nazwa):
self.nazwa = nazwaself.nazwa = nazwa
Relacje: wiele-do-jednego
class Czasopisma(Baza):
class Czasopisma(Baza):
__tablename__ = 'czasopisma'__tablename__ = 'czasopisma'
id = Column(Integer,primary_key = True)id = Column(Integer,primary_key = True) nazwa = Column(String(100))nazwa = Column(String(100))
id_kat = id_kat =
Column(Integer,ForeignKey('kategorie.id')) Column(Integer,ForeignKey('kategorie.id')) wydanie_id = Column(Integer, wydanie_id = Column(Integer,
ForeignKey('wydania.id')) ForeignKey('wydania.id'))
wydania = relationship("Wydania", wydania = relationship("Wydania", backref="czasopismo")
backref="czasopismo")
def __init__ (self, nazwa):def __init__ (self, nazwa):
self.nazwa = nazwaself.nazwa = nazwa
Relacje: wiele-do-jednego
class Wydania(Baza):
class Wydania(Baza):
__tablename__ = 'wydania'__tablename__ = 'wydania'
id = Column(Integer, primary_key=True)id = Column(Integer, primary_key=True) issue = Column(String(100))issue = Column(String(100))
Relacje: jeden-do-jednego
class Autorzy(Baza):
class Autorzy(Baza):
__tablename__ = 'autorzy'__tablename__ = 'autorzy'
id = Column(Integer, primary_key = True)id = Column(Integer, primary_key = True) imie = Column(String(100))imie = Column(String(100))
nazwisko = Column(String(100))nazwisko = Column(String(100))
telefon = relationship("Telefony", uselist=False, telefon = relationship("Telefony", uselist=False, backref="autor")
backref="autor")
Relacje: jeden-do-jednego
#zakladajac, ze ma tylko jeden telefon
#zakladajac, ze ma tylko jeden telefon class Telefony(Baza):
class Telefony(Baza):
__tablename__ = 'telefony'__tablename__ = 'telefony'
id = Column(Integer, primary_key = True)id = Column(Integer, primary_key = True) autor_id = Column(Integer, autor_id = Column(Integer,
ForeignKey('autorzy.id')) ForeignKey('autorzy.id'))
Relacje: wiele-do-wielu
#wielu autorów ma wiele artykułów
#tablica asocjacyjna – fizycznie tabela na bazie aut_art = Table('aut_art', Baza.metadata,
aut_art = Table('aut_art', Baza.metadata,
Column('autor_id', Integer, Column('autor_id', Integer, ForeignKey('autorzy.id')),
ForeignKey('autorzy.id')),
Column('artykul_id', Integer, Column('artykul_id', Integer, ForeignKey('artykuly.id'))
ForeignKey('artykuly.id')) ))
Relacje: wiele-do-wielu
class Artykuly(Baza):
class Artykuly(Baza):
__tablename__ = 'artykuly'__tablename__ = 'artykuly'
id = Column(Integer, primary_key = True)id = Column(Integer, primary_key = True) tytul = Column(String(300))tytul = Column(String(300))
abstrakt = Column(String)abstrakt = Column(String)
autorzy = relationship("Autorzy", autorzy = relationship("Autorzy",
secondary=aut_art, backref=”artykuly”) secondary=aut_art, backref=”artykuly”)
Relacje: wiele-do-wielu
class Autorzy(Baza):
class Autorzy(Baza):
__tablename__ = 'autorzy'__tablename__ = 'autorzy'
id = Column(Integer, primary_key = True)id = Column(Integer, primary_key = True) imie = Column(String(100))imie = Column(String(100))
nazwisko = Column(String(100))nazwisko = Column(String(100))
telefon = relationship("Telefony", uselist=False, telefon = relationship("Telefony", uselist=False, backref="autor")
backref="autor")
Odwołania do relacyjnych obiektów
kategoria.czasopisma = kategoria.czasopisma =
[czasopismo, czas2]
[czasopismo, czas2]
print kategoria.czasopisma print kategoria.czasopisma
for c in kategoria.czasopisma:
for c in kategoria.czasopisma:
print ' ', c.id, c.nazwa print ' ', c.id, c.nazwa
Zapytania z relacjami
print sesja.query(Czasopisma, print sesja.query(Czasopisma,
Kategorie).join(Kategorie) Kategorie).join(Kategorie)
for c, k in for c, k in
sesja.query(Czasopisma, sesja.query(Czasopisma,
Kategorie).join(Kategorie).all():
Kategorie).join(Kategorie).all():
print c.id, c.nazwa, print c.id, c.nazwa, c.id_kat, k.nazwa
c.id_kat, k.nazwa
Zapytania z relacjami
a_alias = aliased(Czasopisma) a_alias = aliased(Czasopisma)
q = sesja.query(Kategorie).\
q = sesja.query(Kategorie).\
join(Kategorie.czasopisma).\
join(Kategorie.czasopisma).\
join(a_alias, join(a_alias,
Kategorie.czasopisma).\
Kategorie.czasopisma).\
filter(Czasopisma.nazwa=='JDBalan filter(Czasopisma.nazwa=='JDBalan
ce').\
ce').\
filter(a_alias.nazwa=='Journal filter(a_alias.nazwa=='Journal of')of')
print q print q
for t in q.all():
for t in q.all():
print t.id, t.nazwaprint t.id, t.nazwa
Lazy i Eager Loading
Lazy Loading
Lazy Loading – domyślne „leniwe” pobieranie – domyślne „leniwe” pobieranie obiektów
obiektów
kategorie.czasopisma kategorie.czasopisma
Gdy chcemy wyświetlić wartość tego pola, Gdy chcemy wyświetlić wartość tego pola,
wówczas dopiero dokonuje się pobranie obiektów wówczas dopiero dokonuje się pobranie obiektów
z bazy, mimo że operowaliśmy już na obiekcie z bazy, mimo że operowaliśmy już na obiekcie
kategorie kategorie
Eager Loading
Eager Loading – „chciwe” pobieranie obiektów. – „chciwe” pobieranie obiektów.
W takim przypadki czasopisma pobrane byłyby W takim przypadki czasopisma pobrane byłyby
od razu przy pobieraniu obiektu kategorie.
od razu przy pobieraniu obiektu kategorie.
Lazy i Eager Loading
jan = jan =
sesja.add(Autorzy(imie='Jan', sesja.add(Autorzy(imie='Jan',
nazwisko='Niejan')) nazwisko='Niejan'))
michal = michal =
sesja.add(Autorzy(imie='Michal', sesja.add(Autorzy(imie='Michal',
nazwisko='Niejan')) nazwisko='Niejan'))
artjana = artjana =
sesja.add(Artykuly('Pewien', sesja.add(Artykuly('Pewien',
'Test', [jan])) 'Test', [jan]))
artjana2 = artjana2 =
sesja.add(Artykuly('Pewien sesja.add(Artykuly('Pewien
Drugi', 'Test', [jan, michal])) Drugi', 'Test', [jan, michal]))
Lazy i Eager Loading
from sqlalchemy.orm import from sqlalchemy.orm import
joinedload, subqueryload, joinedload, subqueryload,
lazyload lazyload
samjan = sesja.query(Autorzy).\
samjan = sesja.query(Autorzy).\
filter_by(imie='Jan')filter_by(imie='Jan')
janart = sesja.query(Autorzy).\
janart = sesja.query(Autorzy).\
options(joinedload('artykuly')).\
options(joinedload('artykuly')).\
filter_by(imie='Jan')filter_by(imie='Jan') print samjan
print samjan print janart print janart
Lazy i Eager Loading
SELECT autorzy.id AS autorzy_id, SELECT autorzy.id AS autorzy_id,
autorzy.imie AS autorzy_imie, autorzy.imie AS autorzy_imie,
autorzy.nazwisko AS autorzy.nazwisko AS
autorzy_nazwisko autorzy_nazwisko
FROM autorzy FROM autorzy
WHERE autorzy.imie = :imie_1 WHERE autorzy.imie = :imie_1
Lazy i Eager Loading
SELECT autorzy.id AS autorzy_id, SELECT autorzy.id AS autorzy_id,
autorzy.imie AS autorzy_imie, autorzy.imie AS autorzy_imie,
autorzy.nazwisko AS autorzy_nazwisko, autorzy.nazwisko AS autorzy_nazwisko,
artykuly_1.id AS artykuly_1_id, artykuly_1.id AS artykuly_1_id,
artykuly_1.tytul AS artykuly_1_tytul, artykuly_1.tytul AS artykuly_1_tytul,
artykuly_1.abstrakt AS artykuly_1.abstrakt AS
artykuly_1_abstrakt artykuly_1_abstrakt
FROM autorzy LEFT OUTER JOIN aut_art AS FROM autorzy LEFT OUTER JOIN aut_art AS
aut_art_1 ON autorzy.id = aut_art_1 ON autorzy.id =
aut_art_1.autor_id LEFT OUTER JOIN aut_art_1.autor_id LEFT OUTER JOIN
artykuly AS artykuly_1 ON artykuly_1.id = artykuly AS artykuly_1 ON artykuly_1.id =
aut_art_1.artykul_id aut_art_1.artykul_id
WHERE autorzy.imie = :imie_1 WHERE autorzy.imie = :imie_1
Lazy i Eager Loading
Można również pobierać te dodatkowe obiekty Można również pobierać te dodatkowe obiekty
przez podzapytania.
przez podzapytania.
Domyślne pobieranie zmieniamy w
Domyślne pobieranie zmieniamy w relationshiprelationship::
relationship("Czasopisma", relationship("Czasopisma", lazy='joined')
lazy='joined')
relationship("Czasopisma", relationship("Czasopisma", lazy='subquery')
lazy='subquery')
Głębsze wnikanie w obiekty odbywa się Głębsze wnikanie w obiekty odbywa się
klasycznie:
klasycznie:
joinedload('autorzy.telefony') joinedload('autorzy.telefony')
A szersze, np.:
A szersze, np.: lazyload('*')lazyload('*')
Lub wybiórczo względem deklaracji:
Lub wybiórczo względem deklaracji:
lazyload('select') lazyload('select')
Zdarzenia
Możemy dodefiniować też zdarzenia, które Możemy dodefiniować też zdarzenia, które
wyzwalają się w zależności od określonych przez wyzwalają się w zależności od określonych przez
nas zmian.
nas zmian.
Przykład Przykład
artjana = Artykuly('Pewien', artjana = Artykuly('Pewien',
'Test', [jan]) 'Test', [jan])
sesja.add(artjana) sesja.add(artjana)
Zdarzenia
from sqlalchemy import event from sqlalchemy import event def obserwator(obserwowany, def obserwator(obserwowany,
wartosc, starawartosc, wartosc, starawartosc,
wyzwalacz):
wyzwalacz):
print "cos sie stalo z %s" % print "cos sie stalo z %s" % obserwowany
obserwowany
event.listen(Artykuly.abstrakt, event.listen(Artykuly.abstrakt,
'set', obserwator, retval=True) 'set', obserwator, retval=True)
print artjana print artjana
artjana.abstrakt = "inny test"
artjana.abstrakt = "inny test"
SQLAlchemy Core
Ta część SQLAlchemy oferuje możliwość Ta część SQLAlchemy oferuje możliwość
budowania bazy danych na podstawie schematu.
budowania bazy danych na podstawie schematu.
Podejście i sposób tworzenia tabel może się Podejście i sposób tworzenia tabel może się
wydawać podobny, ale samo podejście jest wydawać podobny, ale samo podejście jest
zupełnie inne. ORM służy do modelowania, zaś zupełnie inne. ORM służy do modelowania, zaś Core jedynie do tworzenia tabel, powiązań, itp., Core jedynie do tworzenia tabel, powiązań, itp.,
na podstawie schematu.
na podstawie schematu.
Ze względu na większą „niskopoziomowość”
Ze względu na większą „niskopoziomowość”
Core, dalsza część będzie jedynie przeglądem Core, dalsza część będzie jedynie przeglądem
ciekawszych możliwości.
ciekawszych możliwości.
Dostęp do tabel
for t in metadata.sorted_tables:
for t in metadata.sorted_tables:
print t.name print t.name
Tworzenie tabel
engine = engine =
create_engine(’sqlite:///:memory:
create_engine(’sqlite:///:memory:
’)’)
metadata = MetaData() metadata = MetaData()
user = Table(’user’, metadata, user = Table(’user’, metadata,
Column(’user_id’, Integer, Column(’user_id’, Integer,
primary_key = True), primary_key = True),
Column(’user_name’, String(16), Column(’user_name’, String(16),
nullable = False), nullable = False),
Column(’email_address’, Column(’email_address’,
String(60), key=’email’), String(60), key=’email’),
Column(’password’, String(20), Column(’password’, String(20),
nullable = False)) nullable = False))
Tworzenie tabel
user_prefs = Table(’user_prefs’, user_prefs = Table(’user_prefs’,
metadata, metadata,
Column(’pref_id’, Integer, Column(’pref_id’, Integer,
primary_key=True), primary_key=True),
Column(’user_id’, Integer, Column(’user_id’, Integer,
ForeignKey("user.user_id"), ForeignKey("user.user_id"),
nullable=False), nullable=False),
Column(’pref_name’, String(40), Column(’pref_name’, String(40),
nullable=False), nullable=False),
Column(’pref_value’, String(100)) Column(’pref_value’, String(100)) ))
metadata.create_all(engine) metadata.create_all(engine)
Tworzenie i usuwanie tabel
employees.create(engine, employees.create(engine,
checkfirst=True) checkfirst=True)
employees.drop(engine, employees.drop(engine,
checkfirst=False) checkfirst=False)
Zmiana schematu tabel
ALTER TABLE
ALTER TABLE poprzez poprzez execute()execute() - czyli - czyli czystym SQLem, albo...
czystym SQLem, albo...
SQLAlchemy-Migrate SQLAlchemy-Migrate
Triggery
t = Table(’test’, meta, t = Table(’test’, meta,
Column(’abc’, String(20), Column(’abc’, String(20),
server_default=FetchedValue()), server_default=FetchedValue()),
Column(’def’, String(20), Column(’def’, String(20),
server_onupdate=FetchedValue()) server_onupdate=FetchedValue()) ))
Sekwencje
table = Table("cartitems", meta, table = Table("cartitems", meta,
Column("cart_id", Integer, Column("cart_id", Integer,
Sequence(’cart_id_seq’), Sequence(’cart_id_seq’),
primary_key=True), primary_key=True),
Column("description", Column("description",
String(40)), String(40)),
Column("createdate", DateTime()) Column("createdate", DateTime()) ))
seq = Sequence(’some_sequence’) seq = Sequence(’some_sequence’)
nextid = connection.execute(seq) nextid = connection.execute(seq)
Wartości domyślne
Table("mytable", meta, Table("mytable", meta,
Column("somecolumn", Integer, Column("somecolumn", Integer,
default=12) default=12) ))
Table("mytable", meta, Table("mytable", meta,
Column("somecolumn", Integer, Column("somecolumn", Integer,
onupdate=25) onupdate=25) ))
Wartości domyślne po stronie SZBD
t = Table(’test’, meta, t = Table(’test’, meta,
Column(’abc’, String(20), Column(’abc’, String(20),
server_default=’abc’), server_default=’abc’),
Column(’created_at’, DateTime, Column(’created_at’, DateTime, server_default=text("sysdate")) server_default=text("sysdate")) ))
Inserty
ins = ins =
Uzytkownik.insert().values(imie=’
Uzytkownik.insert().values(imie=’
Jack’, nazwisko=’The Ripper’) Jack’, nazwisko=’The Ripper’)
str(ins) str(ins)
result = conn.execute(ins) result = conn.execute(ins)
Selekty
s = select([Uzytkownik]) s = select([Uzytkownik]) result = conn.execute(s) result = conn.execute(s)
for row in result:
for row in result:
print row print row
Złączenia
print Kategorie.join(Czasopisma) print Kategorie.join(Czasopisma)
s = select([users.c.fullname], s = select([users.c.fullname],
from_obj=[
from_obj=[
users.join(addresses, users.join(addresses,
addresses.c.email_address.like(us addresses.c.email_address.like(us
ers.c.name + ’%’)) ers.c.name + ’%’)) ])])
print conn.execute(s).fetchall() print conn.execute(s).fetchall()
również
również outerjoin() outerjoin()
Parametryzowanie zapytań
from sqlalchemy.sql import from sqlalchemy.sql import
bindparam bindparam s = s =
users.select(users.c.name==bindpa users.select(users.c.name==bindpa
ram(’username’)) ram(’username’)) conn.execute(s, conn.execute(s,
username=’wendy’).fetchall() username=’wendy’).fetchall()
Podpięte funkcje pythona
i = 0 i = 0
def mydefault():
def mydefault():
global i global i
i += 1 i += 1
return i return i
t = Table("mytable", meta, t = Table("mytable", meta,
Column(’id’, Integer,
Column(’id’, Integer, primary_key=True,
primary_key=True, default=mydefault), default=mydefault),
))
Funkcje
from sqlalchemy.sql import func from sqlalchemy.sql import func
print func.now() print func.now()
print func.concat(’x’, ’y’) print func.concat(’x’, ’y’)
print print
func.xyz_my_goofy_function() func.xyz_my_goofy_function()
print func.current_timestamp() print func.current_timestamp()
print conn.execute(
print conn.execute(
select([func.max(addresses.c.emai select([func.max(addresses.c.emai
l_address, l_address,
type_=String).label(’maxemail’)]) type_=String).label(’maxemail’)]) ).scalar()).scalar()
Unie
from sqlalchemy.sql import union from sqlalchemy.sql import union
u = union(
u = union(
addresses.select(addresses.c.emai addresses.select(addresses.c.emai
l_address==’foo@bar.com’), l_address==’foo@bar.com’),
addresses.select(addresses.c.emai addresses.select(addresses.c.emai
l_address.like(’%@yahoo.com’)), l_address.like(’%@yahoo.com’)),
).order_by(addresses.c.email_add).order_by(addresses.c.email_add ress)
ress)
print conn.execute(u).fetchall() print conn.execute(u).fetchall()
podobnie
podobnie intersect, intersect_all, intersect, intersect_all, except_all
except_all
Zliczanie
print conn.execute(select([
print conn.execute(select([
users.c.name, users.c.name,
select([func.count(addresses.c.id select([func.count(addresses.c.id )], )],
users.c.id==addresses.c.user_id).
users.c.id==addresses.c.user_id).
as_scalar() as_scalar()
])).fetchall() ])).fetchall()
Podzapytania
s = select([users.c.name], s = select([users.c.name],
users.c.id==select([users.c.id]).
users.c.id==select([users.c.id]).
correlate(None)) correlate(None))
print s print s
Grupowania, having, order by
s = select([addresses.c.user_id, s = select([addresses.c.user_id,
func.count(addresses.c.id)]).\
func.count(addresses.c.id)]).\
group_by(addresses.c.user_id).hav group_by(addresses.c.user_id).hav ing(func.count(addresses.c.id)>1) ing(func.count(addresses.c.id)>1)
print conn.execute(s).fetchall() print conn.execute(s).fetchall() s = s =
select([addresses.c.email_address select([addresses.c.email_address
, addresses.c.id]).distinct().\
, addresses.c.id]).distinct().\
order_by(addresses.c.email_addres order_by(addresses.c.email_addres
s.desc(), addresses.c.id) s.desc(), addresses.c.id)
conn.execute(s).fetchall() conn.execute(s).fetchall()
Jednoczesne wstawianie do wielu
stmt = users.update().\
stmt = users.update().\
values(name=’ed wood’).\
values(name=’ed wood’).\
where(users.c.id==addresses.c.id) where(users.c.id==addresses.c.id) .\.\
where(addresses.c.email_address.s where(addresses.c.email_address.s
tartswith(’ed%’)) tartswith(’ed%’))
conn.execute(stmt) conn.execute(stmt)
Usuwanie
conn.execute(users.delete().where conn.execute(users.delete().where
(users.c.name > ’m’)) (users.c.name > ’m’))
Modelowanie
Encje (leniwe, ale nie anemiczne) Encje (leniwe, ale nie anemiczne)
Obiekty wartości Obiekty wartości
Kontekst Kontekst
Źródła
Informacje zaczerpnięte z dokumentacji:
Informacje zaczerpnięte z dokumentacji:
http://media.readthedocs.org/pdf/
http://media.readthedocs.org/pdf/
sqlalchemy/latest/sqlalchemy.pdf sqlalchemy/latest/sqlalchemy.pdf
Komunikacja internetowa
Implementacja komunikacji internetowej i programowanie usług sieciowych
Gniazda/Socket
Mechanizm Internet Process Communication.
Mechanizm Internet Process Communication.
Służy do dwukierunkowej komunikacji Służy do dwukierunkowej komunikacji
internetowej na niskim poziomie. Charakteryzuje internetowej na niskim poziomie. Charakteryzuje
ją domena adresowa, sposób komunikacji i ją domena adresowa, sposób komunikacji i
protokół sieciowy.
protokół sieciowy.
Gniazda/Socket
Domeny:
Domeny:
socket.AF_UNIX
socket.AF_UNIX – w obrębie jednej maszyny – w obrębie jednej maszyny socket.AF_INET
socket.AF_INET – po IPv4 – po IPv4 socket.AF_INET6
socket.AF_INET6 – po IPv6 – po IPv6
Gniazda/Socket
Typy:
Typy:
socket.SOCK_STREAM
socket.SOCK_STREAM – dwukierunkowa, – dwukierunkowa, połączeniowa
połączeniowa
socket.SOCK_DGRAM
socket.SOCK_DGRAM – bezpołączeniowa – bezpołączeniowa korzystająca z datagramów (jednostka danych) korzystająca z datagramów (jednostka danych)
socket.SOCK_RAW
socket.SOCK_RAW – surowe pakiety – surowe pakiety socket.SOCK_RDM
socket.SOCK_RDM - zaufane wiadomości - zaufane wiadomości bezpołączeniowe
bezpołączeniowe
socket.SOCK_SEQPACKET
socket.SOCK_SEQPACKET – zaufane – zaufane wiadomości zorientowane na połączenie wiadomości zorientowane na połączenie
Gniazda/Socket
Protokoły:
Protokoły:
TCP – połączeniowy TCP – połączeniowy
UDP – bezpołączeniowy UDP – bezpołączeniowy
Często protokoły są wymuszane przez domenę i Często protokoły są wymuszane przez domenę i
typ.
typ.
Echo
Przykład:
Przykład:
#!/usr/bin/env python
#!/usr/bin/env python from socket import * from socket import *
ip_serwera = "127.0.0.1"
ip_serwera = "127.0.0.1"
port_serwera = 9000 port_serwera = 9000
gniazdo = socket(AF_INET, SOCK_STREAM) gniazdo = socket(AF_INET, SOCK_STREAM)
gniazdo.bind((ip_serwera, port_serwera)) gniazdo.bind((ip_serwera, port_serwera))
gniazdo.listen(1) gniazdo.listen(1)
Echo
while 1:
while 1:
polaczenie, adres = gniazdo.accept()polaczenie, adres = gniazdo.accept() print "Polaczono", adresprint "Polaczono", adres
while 1:while 1:
dane = polaczenie.recv (1024)dane = polaczenie.recv (1024)
if dane.strip() == "END":if dane.strip() == "END":
polaczenie.close()polaczenie.close()
exit()exit()
else:else:
polaczenie.send (dane)polaczenie.send (dane)
Echo
Użyteczne narzędzia:
Użyteczne narzędzia:
telnet localhost 9000 telnet localhost 9000
nmap -v localhost nmap -v localhost
fuser -k 9000/tcp fuser -k 9000/tcp
Architektura Klient-Serwer
Klasyczna architektura sposobu przetwarzania Klasyczna architektura sposobu przetwarzania
informacji.
informacji.
Jedna aplikacja oferuje usługi, druga ich żąda.
Jedna aplikacja oferuje usługi, druga ich żąda.
Architektura Klient-Serwer
s = socket.socket(
s = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)socket.AF_INET, socket.SOCK_STREAM) s.connect(("umcs.pl", 80))
s.connect(("umcs.pl", 80))
Architektura Klient-Serwer
serversocket = socket.socket(
serversocket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)socket.AF_INET, socket.SOCK_STREAM) serversocket.bind((socket.gethostname(), 80)) serversocket.bind((socket.gethostname(), 80))
serversocket.listen(5) serversocket.listen(5)
Socket
socket.getdefaulttimeout()
socket.getdefaulttimeout() - domyślny timeout w - domyślny timeout w sekundach
sekundach
socket.create_connection(address[, timeout[, socket.create_connection(address[, timeout[,
source_address]]) source_address]])
socket.getaddrinfo(host, port, family=0, socket.getaddrinfo(host, port, family=0,
socktype=0, proto=0, flags=0) socktype=0, proto=0, flags=0)
socket.gethostbyname(hostname)
socket.gethostbyname(hostname) – tłumaczy host – tłumaczy host na IPv4
na IPv4
Socket
socket.gethostname()
socket.gethostname() - zwraca hostname maszyny, - zwraca hostname maszyny, na której jest uruchomiony
na której jest uruchomiony
socket.gethostbyaddr(ip_address)
socket.gethostbyaddr(ip_address) – zwraca host – zwraca host pod adresem
pod adresem
socket.socket([family[, type[, proto]]])
socket.socket([family[, type[, proto]]]) – zwraca – zwraca gniazdo
gniazdo
Obiekty typu Socket
socket.accept()
socket.accept() - akceptuje połączenie- akceptuje połączenie socket.bind(address)
socket.bind(address) – podłącza gniazdo do – podłącza gniazdo do (hosta,portu)
(hosta,portu) socket.close()
socket.close() - zamyka połączenie - zamyka połączenie socket.connect(address)
socket.connect(address) – łączy z adresem – łączy z adresem socket.listen(backlog)
socket.listen(backlog) – nakazuje nasłuchiwać – nakazuje nasłuchiwać połączeń w liczbie max. backlog.
połączeń w liczbie max. backlog.
socket.recv(bufsize[, flags])
socket.recv(bufsize[, flags]) – przyjmuje dane – przyjmuje dane wrzucone do gniazda
wrzucone do gniazda
Obiekty typu Socket
socket.recvfrom(bufsize[, flags])
socket.recvfrom(bufsize[, flags]) – dodatkowo – dodatkowo zwraca adres wysyłającego
zwraca adres wysyłającego socket.send(string[, flags])
socket.send(string[, flags]) – wysyła część danych – wysyła część danych i zwraca ile zostało tych danych przesłanych
i zwraca ile zostało tych danych przesłanych socket.sendall(string[, flags])
socket.sendall(string[, flags]) – wysyła wszystkie – wysyła wszystkie danedane
socket.sendto(string[, flags], address)
socket.sendto(string[, flags], address) – wysyła – wysyła konkretnemu adresatowi
konkretnemu adresatowi socket.settimeout(value)
socket.settimeout(value) – ustawia timeout – ustawia timeout
Klient i serwer czasu
#!/usr/bin/env python
#!/usr/bin/env python from socket import * from socket import *
import time import time
ip_serwera = "127.0.0.1"
ip_serwera = "127.0.0.1"
port_serwera = 9000 port_serwera = 9000
gniazdo = socket(AF_INET, SOCK_STREAM) gniazdo = socket(AF_INET, SOCK_STREAM)
gniazdo.bind ((ip_serwera, port_serwera)) gniazdo.bind ((ip_serwera, port_serwera))
gniazdo.listen(10) gniazdo.listen(10)
Klient i serwer czasu
while 1:
while 1:
polaczenie, adres = gniazdo.accept()polaczenie, adres = gniazdo.accept() print "Klient z adresu", adresprint "Klient z adresu", adres
polaczenie.send (time.ctime())polaczenie.send (time.ctime()) polaczenie.close()polaczenie.close()
Klient i serwer czasu
#!/usr/bin/env python
#!/usr/bin/env python from socket import * from socket import *
import sys import sys
gniazdo = socket (AF_INET, SOCK_STREAM) gniazdo = socket (AF_INET, SOCK_STREAM) gniazdo.connect ((sys.argv[1], int(sys.argv[2]))) gniazdo.connect ((sys.argv[1], int(sys.argv[2])))
czas = gniazdo.recv (1024) czas = gniazdo.recv (1024)
gniazdo.close() gniazdo.close()
print "Czas: ", czas print "Czas: ", czas
Demony
Demony to aplikacje serwerowe działające w tle.
Demony to aplikacje serwerowe działające w tle.
Mogą oferować usługi lub wykonywać Mogą oferować usługi lub wykonywać
sukcesywnie jakieś zadanie.
sukcesywnie jakieś zadanie.
Demony
Przykład klasy bazowej demonizującej (źródło:
Przykład klasy bazowej demonizującej (źródło:
http://www.jejik.com/files/examples/daemon.py http://www.jejik.com/files/examples/daemon.py):):
Demony
#!/usr/bin/env python
#!/usr/bin/env python import sys, time
import sys, time
from sander import Daemon from sander import Daemon class MyDaemon(Daemon):
class MyDaemon(Daemon):
def run(self):def run(self):
i = 0i = 0
while True:while True:
f = open('demon.txt','a')f = open('demon.txt','a') f.write(str(i))f.write(str(i))
i=i+1i=i+1
time.sleep(1)time.sleep(1) f.close()f.close()
Demony
if __name__ == "__main__":
if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-daemon = MyDaemon('/tmp/daemon- example.pid')
example.pid')
if len(sys.argv) == 2:if len(sys.argv) == 2:
if 'start' == sys.argv[1]:if 'start' == sys.argv[1]:
daemon.start()daemon.start()
elif 'stop' == sys.argv[1]:elif 'stop' == sys.argv[1]:
daemon.stop()daemon.stop()
elif 'restart' == sys.argv[1]:elif 'restart' == sys.argv[1]:
daemon.restart()daemon.restart()
Demony
else:else:
print "Nieznane polecenie"print "Nieznane polecenie"
sys.exit(2)sys.exit(2)
sys.exit(0)sys.exit(0)
else:else:
print "usage: %s start|stop|restart" % print "usage: %s start|stop|restart" % sys.argv[0]
sys.argv[0]
sys.exit(2)sys.exit(2)
Demony
Dodatkowo można uniezależnić tego demona Dodatkowo można uniezależnić tego demona
nieco od systemu:
nieco od systemu:
if (hasattr(os, "devnull")):
if (hasattr(os, "devnull")):
DEVNULL = os.devnull DEVNULL = os.devnull
else:
else:
DEVNULL = "/dev/null"
DEVNULL = "/dev/null"
Select
Moduł select służy do nasłuchiwania na wielu Moduł select służy do nasłuchiwania na wielu
gniazdach jednocześnie, co pozwala na gniazdach jednocześnie, co pozwala na
obsługiwanie wielu klientów obsługiwanie wielu klientów
select.select(rlist, wlist, xlist[, timeout]) select.select(rlist, wlist, xlist[, timeout])
http://docs.python.org/library/select.html http://docs.python.org/library/select.html
Serwer HTTP
from BaseHTTPServer import HTTPServer from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import from SimpleHTTPServer import
SimpleHTTPRequestHandler SimpleHTTPRequestHandler
import os import os
os.chdir(".") os.chdir(".")
serv = HTTPServer(("",8888), serv = HTTPServer(("",8888),
SimpleHTTPRequestHandler) SimpleHTTPRequestHandler)
serv.serve_forever() serv.serve_forever()
Usługi
python-dnspython – do pracy jako serwer DNS python-dnspython – do pracy jako serwer DNS
httplib – protokół HTTP httplib – protokół HTTP
imaplib – protokół IMAP (poczta) imaplib – protokół IMAP (poczta)
python-zsi – pakiet do tworzenia klienta i serwera python-zsi – pakiet do tworzenia klienta i serwera SOAPSOAP
Usługi: POP
Do obsługi poczty służy pakiet POP.
Do obsługi poczty służy pakiet POP.
Przykład:
Przykład:
import getpass, poplib import getpass, poplib
#http://docs.python.org/library/poplib.html
#http://docs.python.org/library/poplib.html
#http://docs.python.org/library/getpass.html
#http://docs.python.org/library/getpass.html s = poplib.POP3("poczta.o2.pl")
s = poplib.POP3("poczta.o2.pl") user = raw_input("Login:")
user = raw_input("Login:")
password = getpass.getpass("Haslo:") password = getpass.getpass("Haslo:")
s.user(user) s.user(user)
s.pass_(password) s.pass_(password)
Usługi: POP
#s.apop(user,password)
#s.apop(user,password) print s.stat()
print s.stat()
print s.stat()[0]
print s.stat()[0]
s.retr(s.stat()[0]) s.retr(s.stat()[0])
top = s.top(s.stat()[0],0) top = s.top(s.stat()[0],0)
print top print top
print filter(lambda item:
print filter(lambda item:
item.startswith('Subject:'), top[1])[0]
item.startswith('Subject:'), top[1])[0]
s.quit() s.quit()
Usługi: FTP – serwer
#!/usr/bin/env python
#!/usr/bin/env python
from pyftpdlib import ftpserver from pyftpdlib import ftpserver
address = ("0.0.0.0", 21) # listen on every IP on address = ("0.0.0.0", 21) # listen on every IP on
my machine on port 21 my machine on port 21
server = ftpserver.FTPServer(address, server = ftpserver.FTPServer(address,
ftpserver.FTPHandler) ftpserver.FTPHandler) server.serve_forever() server.serve_forever()
Komunikacja ze stronami
Do pozyskiwania stron służy m.in. urllib.
Do pozyskiwania stron służy m.in. urllib.
urllib.urlopen(url[, data[, proxies]]) – otwiera url urllib.urlopen(url[, data[, proxies]]) – otwiera url
urllib.urlretrieve(url[, filename[, reporthook[, urllib.urlretrieve(url[, filename[, reporthook[,
data]]]) – pobiera url do pliku data]]]) – pobiera url do pliku
http://docs.python.org/library/urllib.html?
http://docs.python.org/library/urllib.html?
highlight=urllib#urllib highlight=urllib#urllib
Komunikacja ze stronami
Do pozyskiwania stron służy m.in. urllib.
Do pozyskiwania stron służy m.in. urllib.
urllib.urlopen(url[, data[, proxies]]) – otwiera url urllib.urlopen(url[, data[, proxies]]) – otwiera url
urllib.urlretrieve(url[, filename[, reporthook[, urllib.urlretrieve(url[, filename[, reporthook[,
data]]]) – pobiera url do pliku data]]]) – pobiera url do pliku
http://docs.python.org/library/urllib.html?highlight=urllib#urllib http://docs.python.org/library/urllib.html?highlight=urllib#urllib
http://www.boddie.org.uk/python/libxml2dom.html http://www.boddie.org.uk/python/libxml2dom.html
Parser stron
Libxml2dom służy do parsowania stron.
Libxml2dom służy do parsowania stron.
libxml2dom.parseString(s, html=1) libxml2dom.parseString(s, html=1)
doc.getElementsByTagName("div") doc.getElementsByTagName("div")
first.childNodes first.childNodes
hrefs[0].getAttribute("href") hrefs[0].getAttribute("href")
child_node.TEXT_NODE child_node.TEXT_NODE
child_node.nodeValue child_node.nodeValue
Twisted
Twisted to silnik do komunikacji sieciowej.
Twisted to silnik do komunikacji sieciowej.
Twisted - serwery
Klasy serwerowe, które używają Twisted Klasy serwerowe, które używają Twisted
dziedziczą po:
dziedziczą po: twisted.internet.protocol.Protocoltwisted.internet.protocol.Protocol Instancja jest tworzona przy połączeniu i ginie Instancja jest tworzona przy połączeniu i ginie
przy jego zakończeniu.
przy jego zakończeniu.
Konfiguracje persystentne są przechowywane w Konfiguracje persystentne są przechowywane w
klasach dziedziczących po klasie:
klasach dziedziczących po klasie:
twisted.internet.protocol.Factory twisted.internet.protocol.Factory
Metoda
Metoda Factory.buildProtocolFactory.buildProtocol tworzy instancję tworzy instancję Protocol
Protocol dla każdego połączenia. dla każdego połączenia.
Dzięki temu aplikacja może oferować tę samą Dzięki temu aplikacja może oferować tę samą
usługę na wielu portach.
usługę na wielu portach.
Klasy Protocol
Te klasy asynchronicznie odpowiadają na żądania.
Te klasy asynchronicznie odpowiadają na żądania.
Przykład (serwer echa):
Przykład (serwer echa):
from twisted.internet.protocol import Protocol from twisted.internet.protocol import Protocol
class Echo(Protocol):
class Echo(Protocol):
def dataReceived(self, data):def dataReceived(self, data):
self.transport.write(data)self.transport.write(data)
Klasy Protocol
Istotne metody:
Istotne metody:
dataRecieved dataRecieved
connectionMade connectionMade
connectionLost connectionLost