Szkielety tworzenia aplikacji - Instytut Informatyki Teoretycznej i

Transkrypt

Szkielety tworzenia aplikacji - Instytut Informatyki Teoretycznej i
Szkielety tworzenia aplikacji
dr inż. Andrzej Grosser
Instytut Informatyki Teoretycznej i Stosowanej
Politechnika Częstochowska
Rok akademicki 2013/14
Kwestie organizacyjne
Kontakt:
mail: [email protected]
strona: http://icis.pcz.pl/~agrosser
konsultacje: pokój 144, po wcześniejszym umówieniu drogą
mailową
Szkielety tworzenia aplikacji
2
Plan przedmiotu
Wprowadzenie do technologii szkieletowych.
Django
instalacja i konfiguracja,
założenia projektowe
model,
podstawy tworzenia stron - widok
kontroler,
dopracowywanie modelu,
testy,
administrator, użytkownik - wprowadzenie ról,
web services.
Qt
Szkielety tworzenia aplikacji
3
Budowanie aplikacji
Szkielety tworzenia aplikacji
4
MVC
Model-View-Controller
wzorzec projektowy wykorzystywany w inżynierii oprogramowania,
izolujący logikę biznesową od warstwy prezentacji danych,
wspierajacy niezależne projektowanie, realizację i testowanie
poszczególnych elementów aplikacji.
Szkielety tworzenia aplikacji
5
Klocki górą
logika
aplikacji
Szkielety tworzenia aplikacji
6
Klocki górą
logika
aplikacji
interfejs
użytkownika
Szkielety tworzenia aplikacji
7
Klocki górą
logika
aplikacji
interfejs
użytkownika
Szkielety tworzenia aplikacji
8
zarządzanie,
komunikacja
Model
logika biznesowa - model składowania danych
warstwa samodzielna
zmiany w strukturze danych nie wpływają na pozostałe części
aplikacji
przenośny
typy: aktywny i pasywny
Szkielety tworzenia aplikacji
9
Widok
logika prezentacji - interfejs użytkownika
referencje do danych
różnorodność technologii (XHTML, PHP, XML, PDF, FLASH,
RSS, SOAP itd)
pobiera, pokazuje, ale nie modyfikuje danych
łatwa rozbudowa
Szkielety tworzenia aplikacji
10
Kontroler
komunikacja
może zmieniać stan modelu
odświeża widok
przełącza sterowanie
Szkielety tworzenia aplikacji
11
Zastosowanie
duże projekty
przewidziana ciągła ewolucja aplikacji i stosowanych w niej
technologii
duży zespół realizujący aplikację
możliwość wykorzystania części projektu w innych realizacjach
Oracle ADF, Java Swing, Spring Framework, Ruby on Rails,
Django, Symfony i wiele innych
Szkielety tworzenia aplikacji
12
Odmiany
Model-View-Presenter
Presentation-Abstraction-Control
Hierarchical Model-View-Controller
Pasywny widok
Szkielety tworzenia aplikacji
13
Szkielety aplikacji
Szkielety tworzenia aplikacji
14
Szkielety aplikacji
Framework
- szkielet budowy aplikacji. Definiuje strukturę aplikacji oraz ogólny
mechanizm jej działania, dostarcza zestaw komponentów i bibliotek
ogólnego przeznaczenia do wykonywania określonych zadań.
Szkielety tworzenia aplikacji
15
Cechy
gotowy szkielet
narzucony przepływ sterowania
domyślna konfiguracja
komponenty do rozbudowy
zdefiniowana i zamknięta struktura wewnętrzna
Szkielety tworzenia aplikacji
16
Zalety i wady
szybka realizacja projektu
poprawa jakości kodu
większa niezawodność
wsparcie twórców frameworku
Szkielety tworzenia aplikacji
17
Zalety i wady
szybka realizacja projektu
poprawa jakości kodu
większa niezawodność
wsparcie twórców frameworku
złożoność
niższa wydajność
koszt szkoleń
Szkielety tworzenia aplikacji
18
Django
Django
- wysokopoziomowy, framework przeznaczony do tworzenia aplikacji
internetowych, napisany w Pythonie.
nazwę wymawiamy “dżango”
nazwa pochodzi od imienia gitarzysty Django Reinhardta
Powstał pod koniec 2003 roku jako ewolucyjne rozwinięcie
aplikacji internetowych, tworzonych przez grupę programistów
związanych z Lawrence Journal-World
W 2005 roku kod Django został wydany na licencji BSD
Django opiera się na wzorcu projektowym
Model-View-Template
Szkielety tworzenia aplikacji
19
Cechy Django I
Automatycznie generowany i kompletny panel administracyjny,
z możliwością dalszego dostosowywania
Przyjazne adresy dokumentów z możliwością dowolnego ich
kształtowania
Prosty lecz funkcjonalny system szablonów czytelny zarówno
dla grafików jak i dla programistów
Oddzielenie logiki aplikacji (widok) logiki biznesowej (model)
wyglądu (szablony) oraz baz danych
Wsparcie dla wielojęzycznych aplikacji
Bardzo duża skalowalność i wydajność pod obciążeniem
Wydajne systemy cache’owania, obsługa Memcached
Własny, prosty serwer do testowania aplikacji
Szkielety tworzenia aplikacji
20
Cechy Django II
Współpracuje z Apache poprzez WSGI (domyślnie) i mod
python oraz z innymi serwerami poprzez protokoły FastCGI i
SCGI
DRY czyli zasada “nie powtarzaj się” w odniesieniu do
tworzenia aplikacji, (np. strukturę bazy danych Django
generuje ze zwykłych klas Pythona)
Posiada ORM wysokiego poziomu pozwalający na łatwe i
bezpieczne operowania na bazach danych bez użycia SQL
Obsługuje następujące bazy danych: PostgreSQL, MySQL,
SQLite oraz Oracle
Rozpowszechniany jest na licencji BSD
Szkielety tworzenia aplikacji
21
Architektura MVT
Model - opisuje strukturę danych, dotyczy schematu bazy
danych
View - kontroluje jakie dane mają dotrzeć do użytkownika
Template - opisuje jak dane będą prezentowane
Controler - dla Django nadzoruje parsowaniem url
Szkielety tworzenia aplikacji
22
Architektura Django
Szkielety tworzenia aplikacji
23
Moduły Django
Interface administracyjny (CRUD interface)
System uwierzytelniania
System komentarzy
Moduł wsparcia formularzy
Obsługa sesji
Obsługa cache’owania
Moduł internacjonalizacji
Moduł lokalizacji
itd...
Szkielety tworzenia aplikacji
24
Kroki tworzenia aplikacji
zaprojektuj aplikację,
zainstaluj niezbędne składniki,
zdefiniuj ustawienia bazy Settings.py,
zdefiniuj model,
dodaj niezbędne moduły,
napisz szablony,
zdefiniuj warstwę widoku,
zdefiniuj mapowanie url,
testuj aplikację,
wdróż ją.
Szkielety tworzenia aplikacji
25
Instalacja I
Instalacja Pythona - http://www.python.org
Instalacja Apache i mod_pythona
Instalacja SZBD: PostgreSQL, MySQL, Oracle lub SQLite
Instalacja sterowników bazy danych
PostgreSQL - pakiet psycopg
MySQL - MySQLdb
SQLite - pysqlite
Oracle - cx_Oracle
Zapewnienie uprawnień do tworzenia i modyfikowania tabel w
bazie danych
Usunięcie starych wersji Django
Instalacja kodu Django
Instalacja z paczek dla określonych dystrybucji
Instalacja oficjalnego wydania
http://www.djangoproject.com/download/
Szkielety tworzenia aplikacji
26
Instalacja II
Instalacja wersji rozwojowej
svn co http://code.djangoproject.com/svn/django/trunk/
django-trunk
Test poprawności instalacji (np.: import modułu django):
>>> import django
>>> django.VERSION
(1, 1, 0, ’alpha’, 0)
Szkielety tworzenia aplikacji
27
Tworzenie projektu
Projekt to zestaw ustawień dla instancji Django zawierający
konfigurację bazy danych, opcje specyficzne dla Django oraz
ustawienia specyficzne dla aplikacji.
Tworzenie katalogu projektu (nie jest zalecane tworzenie go w
/var/www),
Przejście do katalogu projektu
Wygenerowanie projektu
django-admin.py startproject pracuj
Szkielety tworzenia aplikacji
28
Tworzenie projektu I
Katalog pracuj zawiera plik i podkatalog z czterema plikami:
pracuj/
manage.py
pracuj/
__init__.py
settings.py
urls.py
wsgi.py
__init__.py - plik wymagany przez Pythona,
manage.py - narzędzie wiersza poleceń, które umożliwia
interakcję z projektem Django na wiele sposób (python
manage.py help),
settings.py - ustawienia i konfiguracja dla projektu Django,
urls.py - główny plik odwzorowania adresów URL dla projektu.
Szkielety tworzenia aplikacji
29
Tworzenie projektu I
Uruchomienie serwera deweloperskiego
python manage.py runserver
Pod adresem http://127.0.0.1:8000/ strona powitalna
projektu
Szkielety tworzenia aplikacji
30
Pierwsza strona w Django I
Realizacja widoku:
tworzenie pliku o nazwie views.py o zawartości:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Witaj, świecie!")
Widok jest zwykłą funkcją Pythona, która jako pierwszy
parametr przyjmuje obiekt HttpRequest, a jako odpowiedź
zwraca obiekt HttpResponse.
Szkielety tworzenia aplikacji
31
Pierwsza strona w Django II
edycja pliku urls.py, który domyslnie zawiera:
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns(’’,
# Example:
# (r’^mysite/’, include(’mysite.foo.urls’)),
# Uncomment the admin/doc line below and add ’django.contrib.admindocs
# to INSTALLED_APPS to enable admin documentation:
# (r’^admin/doc/’, include(’django.contrib.admindocs.urls’)),
# Uncomment the next line to enable the admin:
# (r’^admin/(.*)’, admin.site.root),
)
zamieniamy na:
Szkielety tworzenia aplikacji
32
Pierwsza strona w Django III
from django.conf.urls.defaults import *
from pracuj.views import hello
urlpatterns = patterns(’’,
url(r’^hello/$’, hello),
)
adres http://127.0.0.1:8000/hello/
Szkielety tworzenia aplikacji
33
Schemat działania I
Przychodzi żądanie dotyczące /hello/.
Django określa główny plik URLconf, analizując zawartość
zmiennej ROOT_URLCONF.
Django przegląda wszystkie wzorce URL z pliku URLconf w
poszukiwaniu pierwszego pasującego do /hello/.
Jeśli znajdzie dopasowanie, wywołuje powiązaną z nim funkcję
widoku.
Funkcja widoku zwraca HttpResponse.
Django konwertuje HttpResponse na odpowiednią odpowiedź
HTTP zawierająca stronę WWW.
Szkielety tworzenia aplikacji
34
Python - wprowadzenie
Python:
Dynamiczny, obiektowy język programowania ogólnego
przeznaczenia
Został stworzony w 1990 przez Guido van Rossuma jako
następca języka ABC
Nazwa pochodzi od serii komediowej - Latający Cyrk Monty
Pythona
Dwie znacząco się różniące wersje: 3.x, 2.x
Najważniejsze implementacje:
CPython
Jython
IronPython
PyPy
Szkielety tworzenia aplikacji
35
Cechy Pythona I
Najważniejsze cechy Pythona:
czysta, łatwa do czytania składnia,
możliwość introspekcji,
intuicyjne programowanie obiektowe,
naturalny sposób wyrażania kodu proceduralnego,
automatyczne zarządzanie pamięcią,
pełna modułowość, wsparcie dla hierachicznych pakietów,
typy danych wysokiego poziomu,
oparty na wyjątkach system obsługi błędów,
Szkielety tworzenia aplikacji
36
Cechy Pythona II
rozległa biblioteka standardowa,
wiele dodatkowych bibliotek zewnętrznych obejmujących
większość dziedzin zastosowań,
moduły i rozszerzenia mogą być łatwo zapisywane w C, C++
(lub Javie dla Jythona, językach .NET dla IronPython),
przenośny na różne platformy systemowe - Windows,
Linux/Unix, Mac,
możliwość osadzenia w aplikacjach jako języka skryptowego.
Szkielety tworzenia aplikacji
37
Interpreter Pythona
Uruchamianie trybu interaktywnego:
python
Powoduje to przejście do:
Python 2.7.2 (default, Jan 31 2012, 13:19:49)
[GCC 4.6.2 20120120 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
Uruchamianie skryptu:
python nazwa_skryptu.py
Powoduje to kompilację i uruchomienie skryptu. Powstają plik z
bajtkodem maszyny wirtualnej Pythona *.pyc
Szkielety tworzenia aplikacji
38
Podział aplikacji Pythona
1
Programy składają się z modułów (może być jeden)
2
Moduły zawierają instrukcje
3
Instrukcje są zbudowane z wyrażeń
4
Wyrażenia tworzą i przetwarzają obiekty
Szkielety tworzenia aplikacji
39
Zmienne I
Nie określa się jawnie typu zmiennej - wnioskowanie o typie na
podstawie prawej strony operatora przypisania.
Każda zmienna musi być zdefiniowana
x = 4
s t r = " A l a ␣ma␣ k o t a "
Brak przypisania wartości do zmiennej skutkuje błędem
>>> h
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name ’h’ is not defined
Szkielety tworzenia aplikacji
40
Zmienne II
Można łączyć definicje zmiennych:
x = y = z = 0
Zmienne można redefiniować, ponowne przypisanie nie musi
być do tego samego typu:
x = 4
x = "As "
Szkielety tworzenia aplikacji
41
Podstawowe typy danych
Najważniejsze typy danych Pythona:
liczby
typ logiczny
łańcuchy znaków
listy
krotki
zbiory
słowniki
Szkielety tworzenia aplikacji
42
Liczby i typ logiczny
Typ
Całkowity
Rzeczywisty
Zespolony
Logiczny
Literał
1
1.0
3+1j
True
Zmienna
x=4
y = 2.0
com = 2+2J
b = False
w i d t h = 20
h e i g h t = 45
width ∗ height
2 ∗∗ 100
3 ∗ 3.75 / 1.5
9.0 / 2
1 j ∗ 1J
1 j ∗ complex ( 0 , 1 )
a =1.5+0.5 j
a. real
a . imag
Szkielety tworzenia aplikacji
43
Łańcuchy znaków I
Łańcuchy znaków Pythona
Przechowują dane tekstowe
Można je definiować:
L = " Mielonka "
s t r L = ’ Golonka ’
n a p i s 1 = " Bardzo ␣ d ł u g i ␣ n a p i s ␣ o b e j m u j ą c y ␣ w i e l e \n\
w i e r s z y ␣ t e k s t u ␣−␣ t r z e b a ␣ j a w n i e ␣ dodawać ␣\n\
z n a k i ␣ p r z e j ś c i a ␣ do ␣ nowego ␣ w i e r s z a "
n a p i s 2 = """
Bardzo ␣ d ł u g i ␣ n a p i s a ␣ o b e j m u j ą c y ␣ w i e l e ␣ w i e r s z y
t e k s t u ␣−␣ n i e ␣ t r z e b a ␣ j a w n i e ␣ dodawać
znaków ␣ p r z e j ś c i a ␣ do ␣ nowego ␣ w i e r s z a
"""
Szkielety tworzenia aplikacji
44
Łańcuchy znaków II
Łańcuchy znaków są indeksowane od zera
print ( strL [ 0 ] )
Obliczanie długości łańcucha znaków
print ( len ( s t r L ))
Odwoływanie się do wartości od końca:
p r i n t ( s t r L [ l e n ( s t r L ) −1])
print ( s t r L [ −1])
Wycinki
#Wycina p o d ł a ń c u c h od 3 znaku aż do końca
print ( s t r L [ 2 : len ( s t r L ) ] )
print ( strL [ 2 : ] )
Szkielety tworzenia aplikacji
45
Łańcuchy znaków III
Operacja konkatenacji
wynik = s t r L + L
Mnożenie łańcuchów:
wynik = 3 ∗ s t r L
Łańcuchy znaków są niezmienne - nie można zmienić wartości
znaków składowych. Próba przypisania:
s t r L [ 0 ] = "M"
Zakończy się błędem:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ’str’ object does not support item assignment
Szkielety tworzenia aplikacji
46
Łańcuchy znaków IV
Operacje możliwe do wykonania na łańcuchach znaków:
s t r L . f i n d ( ’ Go ’ )
s t r L . r e p l a c e ( ’ Go ’ , ’ Mie ’ )
n a p i s = " kot , p i e s , r y b k a " )
napis . s p l i t ( ’ , ’ )
"%s ␣%s " % ( " G o l o n k a " , " M i e l o n k a " )
#W e r s j a >= 2 . 6
" {0} ␣ {1} " . format ( " G o l o n k a " , " M i e l o n k a " )
Szkielety tworzenia aplikacji
47
Listy I
Listy są uporządkowaną kolekcją elementów, elementy
umieszcza się pomiędzy parą nawiasów kwadratowych []
l s t = [1 , 2 , 3]
Długość listy:
len ( l s t )
Nie muszą zawierać elementów tego samego typu, mogą nawet
zawierać listy zagnieżdżone:
l s t 2 = [ 1 , " Kot " , 3 . 0 ]
l s t 3 = [ [ 1 , " Kot " ] , 3 . 0 ]
Konkatenacja lista
lst2 + lst3
Szkielety tworzenia aplikacji
48
Listy II
Podobnie jak dla łańcuchów znaków mogą być robione wycinki
z list:
lst2 [1:]
lst2 [1:2]
l s t [: −1]
Można zmieniać elementy listy (inaczej niż dla łańcuchów
znaków):
lst2 [0] = 2
Operacje specyficzne dla list
l s t 1 . append ( [ 1 , 2 , 3 ] )
l s t 1 . pop ( 1 )
del l s t 1 [ 1 ]
Szkielety tworzenia aplikacji
49
Listy III
Sprawdzanie zakresów indeksów - przekroczenie zakresu
indeksów skutkuje błędem
lst1 [10]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
Wyrażenia listowe (ang. list comprehension)
l s t 4 = [ e l e m e n t ∗2 f o r e l e m e n t i n [ 1 , 2 , 3 ] ]
Szkielety tworzenia aplikacji
50
Krotki I
Krotki są niezmienną sekwencją elementów (nie da się zmieniać
wartości elementów składowych krotki po jej utworzeniu).
Używane najczęściej w sytuacji, gdy nie powinno się zmieniać
elementów zawartych w kolekcji.
Kolejne elementy krotki rozdziela się przecinkami:
t = 12345 , 6789 , ’ w i t a j ! ’
Krotki można zagnieżdżać:
u = t , (1 , 2 , 3 , 4 , 5)
Szkielety tworzenia aplikacji
51
Krotki II
Liczba elementów w krotce
len ( t )
Odwołanie do elementów za pomocą indeksów, możliwe jest
również robienie wycinków z krotek:
t [0]
t [1:3]
Rozpakowanie krotki
x, y, z = t
Szkielety tworzenia aplikacji
52
Zbiory I
Zbiory są nieuporządkowaną kolekcją bez powtórzeń:
#l s t − l i s t a , zb − z b i ó r
l s t = [ " kot " , " p i e s " , " kanarek " , " kot " , " kura " ,\
" p i e s " , " kot " ]
zb = s e t ( l s t )
Sprawdzanie przynależności do zbioru:
" k a n a r e k " i n zb
" s k o w r o n e k " i n zb
Szkielety tworzenia aplikacji
53
Zbiory II
Operacje na zbiorach:
a = set ( ’ abcdef ’ )
b = s e t ( ’ abcmz ’ )
#R ó ż n i c a z b i o r ó w
a − b
#Suma z b i o r ó w
a | b
#C z ę ś ć w s p ó l n a
a & b
#R ó ż n i c a s y m e t r y c z n a
a ^ b
Szkielety tworzenia aplikacji
54
Słowniki I
Słowniki są kontenerem przechowującym pary klucz - wartość.
Kolejne rozdzielane przecinkami pary są zapisane pomiędzy
nawiasami klamrowymi
t e l e f o n y = { ’ A l e k ’ : 1 2 3 4 5 , ’ Tadek ’ : 1 1 1 1 1 }
Odwołanie do wartości pod kluczem:
t e l e f o n y [ ’ Alek ’ ]
Przypisanie wartości do nieistniejącego klucza powoduje
dodanie nowej pary:
t e l e f o n y [ ’ R o b e r t ’ ] = 122222
Przejście po elementach słownika:
f o r naz , n r i n t e l e f o n y . i t e r i t e m s ( ) :
p r i n t ( naz , n r )
Szkielety tworzenia aplikacji
55
Słowniki II
Wybór listy kluczy ze słownika:
t e l e f o n y . keys ()
Wybór listy wartości ze słownika:
telefony . values ()
Sprawdzenie czy klucz o podanej wartości istnieje w słowniku:
’Adam ’ i n t e l e f o n y
Szkielety tworzenia aplikacji
56
Pliki I
Python dostarcza operacji dla plików
Zapis danych do pliku:
f = open ( ’ dane . t x t ’ , ’w ’ )
f . w r i t e ( ’ Napis ’ )
f . close ()
Odczyt danych z pliku:
f = open ( ’ dane . t x t ’ )
c a l y P l i k = f . read ()
f . close ()
Szkielety tworzenia aplikacji
57
Instrukcje I
Zbiór instrukcji Pythona:
Instrukcja przypisania
Wywołanie funkcji
Instukcja print
Instrukcja if/elsif/else
Instukcja for
Instukcja while/else
Instukcja pusta pass
Instrukcja break
Instukcja continue
Definicja funkcji def
Szkielety tworzenia aplikacji
58
Instrukcje II
Definicja klasy class
Instrukcja powrotu z funkcji return
Dostęp do modułu import
Dostęp do składowych modułu from
Wychwytywanie wyjątków try/except/finally
Zgłaszanie wyjątków raise
Dostęp do zmiennych globalnych/modułowych global
Tworzenie generatorów yield
Usunięcie nazwy del
Szkielety tworzenia aplikacji
59
Instrukcja warunkowa if I
Ogólna postać (frazy elif, else są opcjonalne):
if expression1 :
statement ( s )
e l i f expression2 :
statement ( s )
e l i f expression3 :
statement ( s )
else :
statement ( s )
Szkielety tworzenia aplikacji
60
Instrukcja warunkowa if II
Przykład:
i f x < 0:
p r i n t ( "X␣ m n i e j s z e ␣ od ␣ z e r a " )
e l i f x == 0 :
p r i n t ( "X␣ równe ␣ z e r o " )
else :
p r i n t ( "X␣ w i ę k s z e ␣ od ␣ z e r a " )
Szkielety tworzenia aplikacji
61
Instrukcja pętli for
Ogólna postać:
for i t e r a t i n g _ v a r in sequence :
statements ( s )
Przykład:
l s t = [ " e g g s " , "spam" , 1 2 0 , 1 2 4 ]
f o r elem i n l s t :
p r i n t ( elem )
f o r i i n range ( 0 , l e n ( l s t ) ) :
print ( l s t [ i ])
Szkielety tworzenia aplikacji
62
Instrukcja pętli while
Postać ogólna, pętla jest wykonywana dopóki wyrażenie ma
wartość logiczną prawdy:
while e x p r e s s i o n :
statement ( s )
Przykład:
licznik = 0
while l i c z n i k < 10:
l i c z n i k += 1
Szkielety tworzenia aplikacji
63
Instrukcje break, else, continue i pass I
break przerywa wykonywanie bieżącej iteracji, wykonanie
instrukcji pętli zostaje przerwane
f o r n i n range ( 2 , 1 0 ) :
f o r x i n range ( 2 , n ) :
i f n % x == 0 :
p r i n t n , ’ równe ’ , x , ’ ∗ ’ , n/ x
break
else :
print n , ’ j e s t ␣ l i c z b ą ␣ pierwszą ’
continue przerywa wykonywanie bieżącej iteracji, następuje
przejście do kolejnej iteracji
Szkielety tworzenia aplikacji
64
Instrukcje break, else, continue i pass II
else jest wykonywane na zakończenie pętli, nie jest
wykonywane w sytuacji, gdy pętla została przerwana instukcją
break
pass jest odpowiednikiem instrukcji pustej z C++
w h i l e True :
pass
Szkielety tworzenia aplikacji
65
Funkcje
Funkcje umożliwiają grupowanie instrukcji w większą całość
Ogólna postać
def nazwa ( l i s t a A r g ) :
instukcje
Argumenty mogą mieć wartość domyślną
Wartości zwracane przez funkcję mogą być różnych typów
Możliwe jest definiowanie funkcji wewnątrz funkcji
Cechą charakterystyczną wsparcie dla wywołań polimorficznych
i duck typing
Szkielety tworzenia aplikacji
66
Definiowanie funkcji
def s i l n i a ( n ) :
""" F u n k c j a ␣ o b l i c z a j ą c a ␣ s i l n i ę """
wynik = 1
f o r i i n range ( 1 , n +1):
w y n i k ∗= i
return wynik
print ( s i l n i a (5))
p r i n t ( s i l n i a . __doc__)
print ( dir ( s i l n i a ))
Szkielety tworzenia aplikacji
67
Argumenty funkcji
Argumenty funkcji są traktowane jako zmienne lokalne, dlatego
zmiany ograniczają się tylko do funkcji
Wyjątkiem od zapisanej zasady są obiekty, których zawartość
może być zmieniana - listy, słowniki, obiekty klas
def z m ian aL ubN ie ( a , b , c ) :
a = 4
b [ 0 ] = 12
c . a = 14
b = 4
c = 4
liczba = 0
l i s t a = [1 , 2 , 3]
obiekt = Prostokat (0)
z m i a n aL ubN ie ( l i c z b a , l i s t a , o b i e k t )
print liczba , l i s t a , obiekt . a
Szkielety tworzenia aplikacji
68
Argumenty domyślne i nazwane funkcji
def a r g D o m y s l n e ( a = 1 , b = 2 , c = 3 ) :
p r i n t " a : { 0 } ␣b : { 1 } ␣ c : { 2 } " . format ( a , b , c )
argDomyslne ( 4 , 6 , 8 )
argDomyslne ( 4 , 6 )
argDomyslne (4)
argDomyslne ( )
argDomyslne ( a = 4)
argDomyslne ( c = 8)
argDomyslne ( c = 8 , b = 4 , a = 2)
Szkielety tworzenia aplikacji
69
Argumenty *args i **kwargs I
Są używane dla funkcji, które przyjmują nieznaną na początku
liczbę argumentów
W przypadku *args - są zbierane argumenty z kolejnych
pozycji i wstawiane do krotki args
def f 1 ( ∗ a r g s ) :
print args
f1 (1 ,2 ,3 ,4 ,5)
W przypadku **kwargs tworzony jest słownik łączący kolejne
nazwy z wartościami argumentów
def f 2 ( ∗ ∗ k w a r g s ) :
p r i n t kwargs
f2 ( a = 1 , b = 2 , c = 3)
Szkielety tworzenia aplikacji
70
Argumenty *args i **kwargs II
def f 2 ( ∗ ∗ k w a r g s ) :
p r i n t kwargs
f2 ( a = 1 , b = 2 , c = 3)
Możliwe jest łączenie obu konwencji
def f 3 ( ∗ a r g s , ∗ ∗ k w a r g s ) :
p r i n t args , kwargs
f3 (1 , 2 , a = 1 , b = 2)
Nie można jednak zamieniać argumentów. Poniższa linia jest
błędna:
f3 ( a = 1 , b = 2 , 1 , 2)
Szkielety tworzenia aplikacji
71
Klasy i obiekty
class Prostokat :
zmienna = 12
def __init__ ( s e l f , a ) :
self .a = a
def p o l e ( s e l f ) :
return s e l f . a ∗ s e l f . a
p = Prostokat (2)
print p . a
Szkielety tworzenia aplikacji
72
Atrybuty
#a t r y b u t k l a s o w y
p r i n t P r o s t o k a t . zmienna
p . nowazmienna = 18
p . zmienna = 1000
#t o n i e j e s t a t r y b u t k l a s o w y
#− t w o r z o n e j e s t p o l e o b i e k t u !
p r i n t p . zmienna
#Odwołanie do z m i e n n e j k l a s o w e j
p r i n t P r o s t o k a t . zmienna
Szkielety tworzenia aplikacji
73
Metody
Metody mogą być wywoływane za pośrednictwem obiektu:
p . pole ()
Można również przekazywać obiekt jako do metod klas jako
pierwszy argument wywołania:
Prostokat . pole (p)
Szkielety tworzenia aplikacji
74
Metody specjalne
Są to metody, których nazwa zaczyna się i kończy od __
Służą do celów specjalnych np: inicjowania, definicji
operatorów, konwersji typów, reprezentacji obiektów klasy w
innej postaci (np. łańcuchów tekstowych)
Szkielety tworzenia aplikacji
75
Dziedziczenie
c l a s s Super :
def __init__ ( s e l f , x ) :
s e l f . zmiennaSuper = x
c l a s s Sub ( S u p e r ) :
def __init__ ( s e l f , x , y ) :
S u p e r . __init__ ( s e l f , x )
s e l f . zmiennaSub = y
s = Sub ( 1 , 2 )
p r i n t s . z m i en n aS u p e r , s . zmiennaSub
Szkielety tworzenia aplikacji
76
Duck typing
c l a s s Kaczka :
def kwacz ( s e l f ) :
p r i n t "Kwaaaa"
c l a s s Wabik :
def kwacz ( s e l f ) :
print " F i i i i "
def k w a k a n i e ( o b i e k t ) :
o b i e k t . kwacz ( )
k = Kaczka ( )
w = Wabik ( )
kwakanie ( k )
k w a k a n i e (w)
Szkielety tworzenia aplikacji
77
Moduły I
Ułatwiają ponowne używanie kodu, mogą zawierać zmienne i
funkcje.
Pozwalają na podział nazw w celu uniknięcia ich konfliktów.
Umożliwiają współdzielenie danych.
Zakres modułu pokrywa się z zakresem pliku.
Kolejne instrukcje są wykonywane tylko raz przy załodowaniu
modułu.
Zawartość modułu można przetwarzać za pomocą dwóćh
instrukcji i funkcja:
Instrukcja import - umożliwia klientowi korzystanie z modułu
jako całości, dostęp do składowych przez kropkę
import o s
o s . name
Szkielety tworzenia aplikacji
78
Moduły II
Instrukcja from - umożliwia w kodzie klienckim korzystanie z
wyszczególnionych nazw bezpośrednio
from s y s import v e r s i o n _ i n f o
version_info ()
Funkcja reload z modułu imp (imp.reload) - umożliwia
ponowne wczytanie modułu
import j a k i s m o d u l
import imp
imp . r e l o a d ( j a k i s m o d u l )
Szkielety tworzenia aplikacji
79
Moduły III
#mojmodul . py
#c o d i n g=u t f 8
x = 10
p r i n t ( "Wywoływane␣ wewnątrz ␣ modułu " )
print (x)
def f u n k c j a ( ) :
print (" funkcja ")
p r i n t ( "Wywoływane␣ wewnątrz ␣ modułu " )
funkcja ()
i f __name__ == "__main__" :
p r i n t " Uruchomiony ␣ j a k o ␣ główny ␣ s k r y p t "
#k l i e n t . py
import mojmodul
mojmodul . f u n k c j a ( )
import imp
imp . r e l o a d ( mojmodul )
Szkielety tworzenia aplikacji
80
Pakiety
Moduły można organizować w hierachiczne struktury, dane są
zorganizowane w strukturach katalogowych.
import k a t a l o g 1 . k a t a l o g 2 . nazwaModulu
Moduł jest traktowany jako pakiet, gdy zawiera plik
__init__.py. Każdy katalog z pakietu musi zawierać ten plik.
Szkielety tworzenia aplikacji
81
Wyjątki
w h i l e True :
try :
l i c z b a = i n t ( raw_input ( "Wprowadź␣ l i c z b ę : " ) )
break
except V a l u e E r r o r :
p r i n t "To␣ n i e ␣ j e s t ␣ poprawna ␣ l i c z b a ! "
Szkielety tworzenia aplikacji
82
Własne typy wyjątków
Można tworzyć własne typy wyjątków
Klasy wyjątków powinny w bezpośredni lub pośredni sposób
dziedziczyć po klasie Exception
c l a s s MojWyjatek ( E x c e p t i o n ) :
def __init__ ( s e l f , w a r t o s c ) :
s e l f . wartosc = wartosc
def __str__ ( s e l f ) :
return repr ( s e l f . wartosc )
try :
r a i s e MojWyjatek ( 2 ∗ 2 )
except MojWyjatek a s e :
print e . wartosc
Szkielety tworzenia aplikacji
83
HTML
HTML - Hyper Text Markup Language
język opisu struktury strony, a nie jej wyglądu
język znaczników, a nie język programowania
zawiera bogaty zbiór znaczników opisujących elementy strony:
nagłówki, akapity, listy i tabele.
przeglądarka poprawnie interpretuje narzucony styl elementu,
dzięki znacznikom w jakich został on osadzony
Szkielety tworzenia aplikacji
84
Historia HTML
1980: fizyk Tim Berners-Lee (CERN) zaproponował
ENQUIRE, do roku 1990 opracował HTML
1993: draft opublikowany przez IETF (Internet Engineering
Task Force)
1995: HTML 2.0
Styczeń 1997: HTML 3.2 (rekomendacja W3C (World Wide
Web Consortium))
Grudzień 1997: HTML 4.0 (rekomendacja W3C) (Strict,
Transitional, Frameset)
1999: HTML 4.01 (rekomendacja W3C)
zawieszenie HTML, prace nad XHTML
2008: working draft HTML5 (prace mają potrwać do 2014)
Szkielety tworzenia aplikacji
85
HTML/XHTML - zasady
znaczniki - słowa kluczowe zawarte w nawiasach kątowych np.:
<table>
znaczniki mogą posiadać atrybuty, których wartości zawarte są
w apostrofach lub w cudzysłowie np: src="przyk.gif"
większa część znaczników wymaga zamknięcia, np.:
<h5>tekst</h5>
znaczniki niepuste zawsze mają znacznik końcowy, np.:
<p>Dowolny tekst</p>
znaczniki puste (logiczne) muszą być zakończone znakiem />,
np.: <br />
wszystkie słowa kluczowe: nazwy znaczników i atrybutów,
powinny być pisane małymi literami, np.:
<img src="przyk.gif" />
pliki mogą nosić rozszerzenie .html lub .htm
Szkielety tworzenia aplikacji
86
Struktura pliku
<html> <!-- otwarcie strony-->
<head> <!-- nagłówek strony-->
<title>Tytuł strony</title>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
</head>
<body> <!-- ciało strony-->
<p>Właściwa zawartość...</p>
</body>
</html> <!-- zamknięcie strony-->
Szkielety tworzenia aplikacji
87
Nowe znaczniki HTML5
Najważniejsze nowe znaczniki:
header - nagłówek
footer - stopka
nav - pasek nawigacyjny
aside - pasek boczny
section - grupowanie powiązanych ze sobą treści
article - samodzielna treść
figure - pozwala powiązać element z podpisem
Szkielety tworzenia aplikacji
88
Struktura pliku HTML5 I
<!DOCTYPE html>
<html>
<head>
<title>Tytuł</title>
<meta charset="UTF-8"/>
</head>
<body>
<header>
<h1>Nagłówek</h1>
</header>
Szkielety tworzenia aplikacji
89
Struktura pliku HTML5 II
<nav>
<ul>
<li><a href="#">Odnośnik1</a></li>
<li><a href="#">Odnośnik2</a></li>
</ul>
</nav>
<section>
<article>
<header>
<h1><a href="#">Tytuł 1</a></h1>
</header>
<section>
<p>Przykładowy wpis</p>
</section>
</article>
</section>
Szkielety tworzenia aplikacji
90
Struktura pliku HTML5 III
<aside>
<h2>Odnośniki:</h2>
<ul>
<li><a href="#">Odnośnik1</a></li>
</ul>
</aside>
<footer>
<p>Struktura HTML5</p>
</footer>
</body>
</html>
Szkielety tworzenia aplikacji
91
Podstawowe znaczniki I
nagłówki
<h1>Nagłówek 1</h1>,
<h2>Nagłówek 2</h2>,
<h3>Nagłówek 3</h3>,
<h4>Nagłówek 4</h4>,
<h5>Nagłówek 5</h5>,
<h6>Nagłówek 6</h6>
paragrafy
<p>Pierwszy paragraf.</p>
<p>Drugi paragraf<br /> ze złamaniem linii.</p>
obrazy
<img src="w3schools.jpg" width="104"
height="142" />
<!-- Komentarz -->
Szkielety tworzenia aplikacji
92
Podstawowe znaczniki II
listy
numerowane - oznaczane liczbami
<ol>
<li>Pierwszy element listy</li>
<li>Drugi element listy</li>
</ol>
wypunktowane - oznaczone kropkami lub symbolami
<ul>
<li>Pierwszy element listy</li>
<li>Drugi element listy</li>
</ul>
definicji
<dl>
<dt>Pojęcie</dt><dd>Definicja</dd>
</dl>
Szkielety tworzenia aplikacji
93
Odnośniki I
<a href="./plik.html" target="_blank">Odniesienie</a>
Rodzaje ścieżek do pliku:
względna - określa położenie pliku z punktu widzenia bieżącej
pozycji w drzewie katalogów:
<a href="./plik.html">Odniesienie</a>
bezwzględna - całkowita ścieżka dostępu do pliku.
<a href="/home/olga/plik.html">Odniesienie</a>
adres URL - całkowita ścieżka dostępu do pliku znajdującego
się na innym serwerze.
<a href="http://icis.pcz.pl/~olga/plik.html">
Odniesienie
</a>
Szkielety tworzenia aplikacji
94
Odnośniki II
Połączenia do określonych miejsc na stronie:
<a href="./plik.html#nazwa">Odniesienie</a>
<!-- W HTML -->
<a name="nazwa">Miejsce odniesienia</a>
<!-- W XHTML -->
<a id="nazwa">Miejsce odniesienia</a>
Szkielety tworzenia aplikacji
95
Style semantyczne
Style semantyczne - określają rolę tekstu w dokumencie:
<em></em> - tekst wyróżniony
<strong></strong> - tekst podwójnie wyróżniony
<code></code> - fragment kodu
<samp></samp> - tekst przykładowy
<var></var> - do nazw zmiennych
<dfn></dfn> - definicja
<cite></cite> - krótki cytat
<address></address> - adresy
<blockquote></blockquote> - blok długiego cytatu
Szkielety tworzenia aplikacji
96
Style prezentacyjne
Style prezentacyjne - określają sposób w jaki tekst powinien zostać
sformatowany:
<b></b> - pogrubienie
<i></i> - kursywa
<tt></tt> - czcionka maszynowa
<sub></sub> - indeks dolny
<sup></sup> - indeks górny
<big></big> - czcionka powiększona
<small></small> - czcionka pomniejszona
Szkielety tworzenia aplikacji
97
Tabele
Tabele ograniczone znacznikiem <table></table>, zawierają:
<thead></thead> - część nagłówkową
<tfoot></tfoot> - stopkę
<tbody></tbody> - "ciało" tabeli
<tr></tr> - wiersze
<th></th> - komórki nagłówka
<td></td> - zwykłe komórki
<colgroup></colgroup> - grupa kolumn
<col /> - atrybuty jednej kolumny
Szkielety tworzenia aplikacji
98
Przykład tabeli
<table border="1">
<thead>
<tr>
<th>nagłówek1</th>
<th>nagłówek2</th>
</tr>
</thead>
<tbody>
<tr>
<td>dane1</td>
<td>dane2</td>
</tr>
</tbody>
</table>
Szkielety tworzenia aplikacji
nagłówek1
dane1
99
nagłówek2
dane2
Formularze
Formularze
używane do przesyłu informacji od użytkownika do serwera
otoczone znacznikiem <form></form> - wewnątrz
poszczególne elementy formularza i kod HTML tworzący cały
układ (akapity, nagłówki, tabele)
na jednej stronie można umieścić dowolną liczbę formularzy,
ale nie wolno ich zagnieżdżać
Szkielety tworzenia aplikacji
100
Formularze cd
<form> zawiera dwa podstawowe atrybuty:
action - względny lub pełny adres URL, pod który należy
przesłać zawartość pól formularza, by otrzymać odpowiedź.
method - metoda przesyłania danych od klienta do serwera:
get - dane formularza są spakowane i dołączone do URL’a,
który został wskazany jako wartość action.
post - dane przesyłane są niezależnie od odwołania do
skryptu. Skrypt otrzymuje je na standardowym wejściu.
Szkielety tworzenia aplikacji
101
Metody get i post
Metoda get
http://server/something?value1=foo&value2=bar
Metoda post
POST /something HTTP/1.1
Host: server
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
value1=foo&value2=bar
Szkielety tworzenia aplikacji
102
Formularze - składowe
Znacznik <input /> definiuje prosty element formularza,
który posiada dwa atrybuty: type i name.
Atrybut type definiuje rodzaj elementu formularza : "text",
"radio", "checkbox", "password", "submit", "reset",
"button", "file", "hidden".
Atrybut name wskazuje nazwę elementu, która jest niezbędna
dla skryptu do odróżnienia poszczególnych pól od siebie.
Skrypt pobiera dane z formularza w postaci: nazwa-wartość.
Jako wartość przyjmowane są rzeczywiste dane wprowadzane
przez użytkownika, natomiast nazwą jest wartość atrybutu
name.
Szkielety tworzenia aplikacji
103
Przykład formularza
<form name="input" action="html_form_action.asp"
method="get">
<p>Czym najczęściej dojeżdżasz do pracy?<br />
<input type="checkbox" name="srodek_kom"
value="Rower" />
Rowerem<br />
<input type="checkbox" name="srodek_kom"
value="Auto" />
Samochodem<br />
<input type="checkbox" name="srodek_kom"
value="ZButa" />
Na piechotę<br /><br />
<input type="submit" value="Zatwierdź" />
</p>
</form>
Szkielety tworzenia aplikacji
104
Przykład formularza cd
Szkielety tworzenia aplikacji
105
Listy wyboru
Opcje wyboru umożliwiają użytkownikowi wybranie z listy
przewijanej jednej lub wielu pozycji.
Opcje wyboru są wprowadzane za pomocą znacznika <select>:
<p>Wybierz wykształcenie
<select name="wyksztalcenie">
<option>Podstawowe</option>
<option>Średnie</option>
<option>Wyższe</option>
</select>
</p>
Szkielety tworzenia aplikacji
106
Obszary tekstowe
Obszary tekstowe są polami wprowadzania danych, w które
użytkownik może wprowadzać wiele linii tekstu.
Do wprowadzania tekstu służy znacznik <textarea>:
<p>wpisz komentarz:<br />
<textarea name="komentarz" rows="10" cols="50">
</textarea>
</p>
Szkielety tworzenia aplikacji
107
Elementy ukryte
Atrybut type znacznika <input /> może przyjąć wartość
"hidden". W takim wypadku element formularza nie będzie
wyświetlany.
<input type="hidden" name="dane_osobowe" value="on">
Mogą być przesyłane w ten sposób dodatkowe dane: numery
ankiety, opis formularza itp.
Szkielety tworzenia aplikacji
108
Przesyłanie plików
<form enctype="multipart/form-data" method="post"
action="http://icis.pcz.pl/cgi-bin/upload">
<p>Wyślij plik:
<input type="file" name="userfile" />
<input type="submit" value="Prześlij" />
</p>
</form>
Szkielety tworzenia aplikacji
109
Zanik struktury HTML
Skutki zaniku struktury w stronach HTML:
utrudnione indeksowanie stron, a co za tym idzie ograniczanie
możliwości narzędzi wyszukujących
obniżenie dostępności strony (np. dla niewidomych)
trudności w zarządzaniu i "konserwacji"
Szkielety tworzenia aplikacji
110
Powstanie CSS
W3C zauważa problem zanikania struktur HTML i zaśmiecania
kodu znacznikami definiującymi wygląd strony. W roku 1995
rozpoczyna budowanie CSS
W 1996 zalecano stosowanie CSS w takim samym stopniu jak
HTML (CSS1 - Cascading Style Sheeets Level 1)
CSS2 - powstał w 1998 roku poszerzając funkcjonalności CSS1
CSS3 - w fazie rozwoju
Szkielety tworzenia aplikacji
111
Podstawowe zalety CSS
możliwość zapanowania nad wyglądem strony bez ingerencji w
jej strukturę
pozwala na wzbogacenie wyglądu strony
umożliwia scentralizowanie opisu wyglądu strony w jednym
miejscu
umożliwia tworzenie stylów dla grup stron
CSS zabezpiecza przed konfliktem reguł (kaskada) zmniejsza
rozmiary plików
Szkielety tworzenia aplikacji
112
Łączenie CSS i HTML
Istnieją trzy możliwości łączenia CSS i HTML:
style wewnętrzne
style osadzone
style zewnętrzne
style importowane
Szkielety tworzenia aplikacji
113
Style wewnętrzne
Do utworzenia stylu wewnętrznego służy w HTML’u atrybut style,
który można użyć zarówno wewnątrz znacznika body, jak i
znaczników definiujących tekst, czy tabele, np.:
<body style="font-family: tahoma, helvetica,
verdana, arial;
font-weight: normal; font-size: 10pt;
text-align: justify;">
<p style="color:gray; padding:5px;"> Tekst </p>
</body>
Szkielety tworzenia aplikacji
114
Style osadzone
Do utworzenia stylu osadzonego (embedded style sheet), służy
znacznik style z nieodłącznym atrybutem type:
<style type="text/css">
body {background:beige;}
h1 {color:gray;}
p {padding:5px;}
</style>
Szkielety tworzenia aplikacji
115
Style zewnętrzne
Styl można opisać w zewnętrznym pliku o rozszerzeniu css i
dołączyć do dokumentu HTML za pomocą znacznika <link>
umieszconego wewnątrz nagłówka:
<head>
<title>Tytuł strony</title>
<link rel="stylesheet" type="text/css"
href="style.css" />
</head>
W zewnętrznym pliku znajduje się kod postaci:
body {background:yellow;}
h1 {text-align:center;}
p {padding:5px;}
Szkielety tworzenia aplikacji
116
Style importowane
Styl można zaimportować z innego serwera:
<head>
<style type="text/css">
@import url(http://www.xyz.pl/styles.css);
</style>
</head>
Szkielety tworzenia aplikacji
117
Budowa reguł (1)
Podstawowy opis elementu struktury w HTML’u miał postać:
<znacznik atrybut1="wartość" atrybut2="wartość2">
tekst
</znacznik>
W CSS, każda reguła składa się z selektora i deklaracji, zawierającej
właściwości i ich wartości:
selektor {
właściwość1:wartość1;
właściwość2:wartość2;
}
Szkielety tworzenia aplikacji
118
Budowa reguł (2)
Selektor określa elementy struktury, do której reguła ma byś
zastosowana,np.:
h1 {text-align:left; color:blue;}
Deklaracja znajdująca się w nawiasach klamrowych, składa się
z właściwości, po której następuje dwukropek, oraz z wartości.
Zapis deklaracji zakończony jest średnikiem.
Wartość może być pojedynczym słowem kluczowym lub
oddzieloną spacjami listą słów kluczowych (dozwoloną dla tej
właściwości). Jeżeli w deklaracji użyto niepoprawnej
właściwości, wtedy cała deklaracja jest ignorowana.
Szkielety tworzenia aplikacji
119
Grupowanie selektorów
Jeżeli chcemy nadać kilku elementom struktury te same
właściwości, nie trzeba powtarzać kilkakrotnie tych samych zapisów
zmieniając jedynie nazwę selektora. Wystarczy zapisać przed jedną
deklaracją listę selektorów, oddzielonych przecinkami.
selektor1, selektor2, ..., selektorN {
wł1:wart1;
wł2:wart2;
}
Na przykład:
body, table, th, td, h3, p {color:gray}
Szkielety tworzenia aplikacji
120
Grupowanie deklaracji
Jeden element może mieć zdefiniowanych wiele właściwości poprzez
umieszczenie wewnątrz nawiasu klamrowego wielu deklaracji:
selektor1 {
wł1:wart1;
wł2:wart2;
...;
włn:wartn;
}
Na przykład:
body
{
font-family: tahoma, helvetica, verdana, arial;
font-weight: normal;
font-size: 10pt;
text-align: justify;
}
Szkielety tworzenia aplikacji
121
Selektory klasy i identyfikatora (1)
Oprócz selektorów elementów dokumentu istnieją jeszcze
selektory klasy oraz selektory identyfikatora, które pozwalają
na przypisanie stylów w sposób niezależny od elementów
dokumentu.
Aby używać selektorów klas, wewnątrz dokumentu HTML
należy dodać atrybuty definiujące klasę:
<znacznik class="nazwa_klasy">.
Wewnątrz definicji stylów należy w takim wypadku użyć
selektora:
znacznik.nazwa_klasy {wlaściwość:wartość;}
lub:
.nazwa_klasy {wlaściwość:wartość;}
Szkielety tworzenia aplikacji
122
Selektory klasy i identyfikatora (2)
Aby używać selektorów identyfikatorów, wewnątrz dokumentu
HTML należy dodać atrybut definiujący:
<znacznik id="identyfikator">.
Wewnątrz definicji stylów należy w takim wypadku użyć
selektora:
#identyfikator {wlaściwość:wartość;}
Różnice pomiędzy selektorami klas i identyfikatorów:
klasy mogą być przyporządkowane dowolnej liczbie elementów
dany identyfikator powinien sie pojawić w dokumencie tylko raz
identyfikator ma wyższy priorytet przy narzucaniu stylu
Szkielety tworzenia aplikacji
123
Pseudoklasy i pseudoelementy
Selektory pseudoklas i pseudoelementów służą do nadawania stylów
elementom o zmiennych stanach, bądź nieistniejących w HTML’u
struktur.
Podstawowe pseudoklasy w CSS to, klasy tyczące połączeń:
a:link - styl łącza jeszcze nieodwiedzanego
a:visited - styl łącza odwiedzonego
a:active - styl łącza uaktywnionego
Podstawowe pseudoelementy w CSS to:
:first-letter - określa odrębny styl dla pierwszej litery
elementu struktury
:first-line - określa odrębny styl dla pierwszej linii
elementu struktury
Szkielety tworzenia aplikacji
124
Drzewo struktur HTML
Szkielety tworzenia aplikacji
125
Selektory kontekstowe
Selektory kontekstowe umożliwiają zdefiniowanie stylu, dla
odpowiedniego elementu wewnątrz drzewa dokumentu HTML.
ul li ul li {color:gray;}
Selektor kontekstowy to kompozycja dwóch lub więcej selektorów
elementów rozgraniczonych spacjami. Każda spacja oznacza
zagnieżdżenie.
Szkielety tworzenia aplikacji
126
Dziedziczenie i wagi
Elementy zagnieżdżone dziedziczą styl, po elemencie
nadrzędnym.
Niewszystkie właściwości są dziedziczone (marginesy, odstępy
od ramek, tło, obramowanie).
W wypadku powtarzających się definicji stylu dla danego
elementu, CSS zabezpiecza się przed konfliktami za pomocą
wag nadawanych poszczególnym regułom:
selektor {właściwość:wartość;} /* 1 */
selektor1 selektor2 {właściwość:wartość;} /* 2 */
.klasa {właściwość:wartość;} /* 10 */
selektor.klasa {właściwość:wartość;} /* 11 */
selektor1.klasa1 selektor2.klasa2 {właściwość:wartość;} /* 22 */
#identyfikator {właściwość:wartość;} /* 100 */
Szkielety tworzenia aplikacji
127
Kaskada
Algorytm kaskady:
Znajdź wszystkie deklaracje zawierające selektory
odpowiadające danemu elementowi.
Posortuj znalezione deklaracje według wag.
Posortuj znalezione deklaracje ze względu na kolejność
występowania (uznaje się, że deklaracje z plików zewnętrznych
są przesłaniane stylami osadzonymi, a te stylami
wewnętrznymi). Zawsze najważniejszy jest styl stojący na
końcu.
Szkielety tworzenia aplikacji
128
Architektura aplikacji Django
Szkielety tworzenia aplikacji
129
Składniki aplikacji Django
URLconf - odpowiedzialne za przetwarzanie adresów URL na
widoki,
Widoki - funkcje przetwarzające żadanie HttpRequest i
zwracające odpowiedź HttpResponse,
Middleware (warstwa pośrednicząca) - umożliwia lekkie,
niskopoziomowe przetwarzanie wejścia-wyjścia Django (żądań,
odpowiedzi, widoki),
Szablony - plik tekstowy zawierający zazwyczaj kod HTML
oraz tagi (kontrola logiki szablonu i przekształcanie treści),
Modele - źródło danych aplikacji, zazwyczaj jest powiązane z
tabelami bazy danych,
ORM - odpowiedzialne za przekształcenie postaci obiektowej
na postać relacyjną.
Szkielety tworzenia aplikacji
130
URLconf I
W celu zaprojektowania URL-i dla aplikacji tworzy się moduł
Pythona nieformalnie zwany URLconf (konfiguracja URL).
Wspomniany moduł jest zaimplementowany w czystym
Pythonie jest prostym mapowaniem pomiędzy wzorcami
adresów URL (zapisanymi jako wyrażenia regularne) a
Pythonowymi funkcjami wywołań zwrotnych (widoków).
Mapowanie to może być, w zależności od potrzeb krótkie lub
długie. Może odwoływać się do innych mapowań i ze względu
na to że jest modułem Pythona może być tworzone
dynamicznie.
Szkielety tworzenia aplikacji
131
URLconf II
Sposób przetwarzania żądania ze strony przez Django:
1
Django określa moduł z głównym URLconf. Zazwyczaj jest
określony przez zawartość zmiennej ROOT_URLCONF,
czasem jest też określane przez atrybut urlconf obiektu
nadchodzącego żadania HttpRequest (ustawione przez warstwę
pośrednią), jej zawartość będzie użyta zamiast zmiennej
ROOT_URLCONF.
2
Django ładuje ten moduł i szuka zmiennej urlpatterns.
Powinna to być lista Pythona, w formacie zwróconym przez
funkcję django.conf.urls.patterns().
3
Django przechodzi po kolei przez każdy wzorzec URL i kończy
przy pierwszym dopasowaniu żądanego adresu URL.
Szkielety tworzenia aplikacji
132
URLconf III
4
Po tym jak jedno z wyrażeń regularnych dopasowuje URL,
Django importuje i wywołuje dany widok, jest nim zwykła
funkcja Pythona. Widok otrzymuje obiekt HttpRequest jako
swój pierwszy argument natomiast resztą argumentów są
wartości przechwycone przez wyrażenie regularne.
5
Jeśli żadne z wyrażeń regularnych nie dopasowało URL-a lub
wywoływany jest wyjątek przy jednym z punktów tego procesu,
Django wywołuje odpowiedni widok obsługi błędów.
Szkielety tworzenia aplikacji
133
URLconf IV
from django.conf.urls import patterns, url, include
urlpatterns = patterns(’’,
(r’^articles/2003/$’, ’news.views.special_case_2003’),
(r’^articles/(\d{4})/$’, ’news.views.year_archive’),
(r’^articles/(\d{4})/(\d{2})/$’, ’news.views.month_archive’),
(r’^articles/(\d{4})/(\d{2})/(\d+)/$’, ’news.views.article_detail’),
)
/articles/2005/03/ dopasowanie do trzeciego wzorca.
/articles/2005/3/ brak dopasowania (wymagane dwie cyfry
miesiąca).
/articles/2003/ dopasowanie do pierwszego wzorca.
/articles/2003 brak dopasowania (brak kończącego /).
/articles/2003/03/03/ dopasowanie do ostatniego wzorca.
Szkielety tworzenia aplikacji
134
Grupy nazwane I
Wcześniejszy przykład używał nienazwanych grup wyrażeń
regularnych (za pomocą nawiasów) do przechwycenia części
URL-a i przekazania ich jako argumentów określonych pozycją
do widoku. W bardziej zaawansowanych zastosowaniach jest
zazwyczaj konieczne używanie nazwanych grup wyrażeń
regularnych do przechwytywania części URL-a i przekazywania
ich do widoku jako argumentów kluczowych.
Składnia Pythona dla nazwanych wyrażeń regularnych (?P<name>pattern) - name jest nazwą grupy a wzorzec jest
używany do dopasowania.
Szkielety tworzenia aplikacji
135
Grupy nazwane II
urlpatterns = patterns(’’,
(r’^articles/2003/$’, ’news.views.special_case_2003’),
(r’^articles/(?P<year>\d{4})/$’, ’news.views.year_archive’),
(r’^articles/(?P<year>\d{4})/(?P<month>\d{2})/$’,
’news.views.month_archive’),
(r’^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$’,
’news.views.article_detail’),
)
Żądanie /articles/2005/03/ wywoła funkcję
news.views.month_archive(request, year=’2005’, month=’03’)
zamiast jak w poprzednim przypadku
news.views.month_archive(request, ’2005’, ’03’).
Szkielety tworzenia aplikacji
136
Funkcje widoku I
Widok (funkcja widoku) jest po prostu funkcją, która
przyjmuje żądanie Http i zwraca odpowiedź Http.
Odpowiedzią może być w zasadzie dowolna: np. strona Html,
przekierowanie do innego adresu, błąd 404, dokument XML,
obrazek itd.
Widok zawiera całą logikę konieczną do przetworzenia żądania
i zwrócenia odpowiedzi.
Kod odpowiedzialny za implementację widoku może co prawda
znajdować się w dowolnym miejscu (jeśli tylko znajduje się na
ścieżkach przeszukiwań Pythona), zazwyczaj jednak
przestrzega się konwencji umieszczając widoki w pliku
views.py znajdującym się w katalogu projektu lub aplikacji.
Szkielety tworzenia aplikacji
137
Funkcje widoku II
from django.http import HttpResponse
def my_view(request):
# ...
if foo:
return HttpResponseNotFound(’<h1>Not found</h1>’)
else:
return HttpResponse(’<h1>Page was found</h1>’
Szkielety tworzenia aplikacji
138
Widoki generyczne I
Tworzenie aplikacji internetowych jest monotonne wymaga
wielokrotnego zapisu pewnych szablonów. Django dostarcza
rozwiązań nie tylko na poziomie modelu i szablonu, lecz
również na poziomie widoku.
Widoki generyczne Django zostały zaprojektowane w celu
ułatwienia tworzenia powtarzalnych zadań - dostarczają
pewnych pewnych idiomów i wzorców na podstawie
tworzonych wcześniej widoków. Wprowadzają warstwę
abstrakcji przez co możliwy jest szybki zapis powtarzalnych
widoków bez potrzeby zapisu dużej ilości kodu.
Można rozpoznać powszechnie używane zadania jak
wyświetlanie listy obiektów i zapisać kod wyświetlający listę
dowolnych obiektów. Wymagany model może być
przekazywany jako dodatkowy argument dla URLconf.
Szkielety tworzenia aplikacji
139
Widoki generyczne II
Django zapewnia łatwy do wykorzystania kod widoków:
wykonujących nieskomplikowane powszechnie wykonywane
zadania: przekierowanie do różnych stron i renderowanie
wybranego szablonu.
wyświetlających listę powiązanych ze sobą obiektów oraz stron
zawierających istotne szczegóły dla pojedynczych obiektów
(lista zamówień klientów i zamówienie dla określonego klienta).
prezentujących oparte na dacie obiekty w postaci stron
zawierających ustalone działania w postaci wykazów
rok/miesiąc/dzień, and stron zawierających ostatnie działania latest (np. archiwum bloga).
umożliwiających użytkownikom tworzenie, aktualizacje i
niszczenie obiektów z i bez autoryzacji.
Szkielety tworzenia aplikacji
140
Widoki generyczne III
Najważniejsze widoki generyczne:
View - klasa bazowa dla wszystkich widoków,
TemplateView - renderuje określony szablon (najczęściej
statyczne widoki),
RedirectView - przekierowanie do określonej strony,
DetailView - strona reprezentująca pojedynczy obiekt,
ListView - reprezentacja listy obiektów,
FormView - widok, który wyświetla formę,
Szkielety tworzenia aplikacji
141
Widoki generyczne IV
{Create,Update,Delete}View - formy do tworzenia, edycji i
niszczenia obiektów,
ArchiveIndexView - strona najwyższego poziomu
prezentująca najnowsze obiekty
{Year,Month,Week,Day,Today}ArchiveView - umożliwia
wyświetlenie obiektów powiązanych z datą.
DateDetailView - pojedynczy obiekt powiązany z datą.
Szkielety tworzenia aplikacji
142
Widoki generyczne V
Przykład wykorzystujący dziedziczenie:
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
Odziedziczony atrybut template_name przechowuje nazwę (ze
ścieżką) szablonu jaki ma zostać użyty (w przykładzie w
katalogu templates został stworzony katalog o nazwie
about.html)
W urls.py dodaje się import:
from book.views import AboutView
Natomiast do reguł mapujących URL-e:
(r’^about/$’, AboutView.as_view()),
Szkielety tworzenia aplikacji
143
Widoki generyczne VI
Po odwołaniu do adresu /about/ zostanie wyświetlona strona
z użyciem szablonu about.html.
Można korzystać także bezpośrednio w urls.py przy mapowaniu
linków na widoki. Wystarczy że zaimportować TemplateView i
użyć:
(r’^about2/$’,
TemplateView.as_view(template_name="about.html")),
Szkielety tworzenia aplikacji
144
Idea szablonów
Umieszczanie kodu HTML w widokach nie jest dobrym
pomysłem - dowolna zmiana projektu strony wymaga zmiany
w kodzie Pythona
Tworzenie kodu Pythona i projektowanie wyglądu strony w
HTML to dwie różne dyscypliny, więc większość
profesjonalnych zespołów rozdziela te zadania na różne osoby
(czasem nawet działy)
Praca posuwa się znacznie sprawniej, jeśli programiści mogą
pracować nad kodem Pythona, a projektanci nad szablonami.
Szkielety tworzenia aplikacji
145
Filozofia i ograniczenia I
Logikę biznesową należy rozdzielić od logiki prezentacyjnej.
Programiści Django widzą system szablonów jako narzędzie
sterujące prezentacją i związaną z tym logiką - to wszystko.
System szablonów nie powinien obsługiwać funkcjonalności
wychodzącej poza ten prosty cel.
Nie można wywołać kodu Pythona bezpośrednio z szablonów.
Całe "programowanie" ogranicza się w zasadzie do tego, co
potrafią znaczniki szablonu. Choć można napisać własny
znacznik, który wykonuje dowolne zadanie, domyślnie szablony
Django nie dopuszczają wykonania dowolnego kodu Pythona.
Szkielety tworzenia aplikacji
146
Filozofia i ograniczenia II
Składnię należy oddzielić od HTML/XML. Choć system
szablonów Django służy przede wszystkim do generowania
kodu HTML, nic nie stoi na przeszkodzie, by stosować go dla
dowolnych formatów innych niż HTML, na przykład zwykłego
tekstu. Niektóre inne języki szablonów bazują na XML,
umieszczając całą logikę szablonu w znacznikach i atrybutach
XML, ale Django celowo unika tego ograniczenia. Wymuszenie
korzystania z XML wprowadza cały wachlarz prostych, ludzkich
pomyłek i trudnych w zrozumieniu komunikatów błędów.
Stosowanie systemu przetwarzania XML wprowadza również
zbyt duży narzut związany z obróbką i renderingiem szablonu.
Szkielety tworzenia aplikacji
147
Filozofia i ograniczenia III
Zakłada się, że projektanci znają kod HTML. System
szablonów nie został zaprojektowany w taki sposób, by
wyglądał ładnie w edytorach WYSIWYG takich jak
Dreamweaver. To zbyt duże ograniczenie, które
uniemożliwiłoby powstanie tak przyjaznej składni. Django
oczekuje, że autorzy szablonów będą potrafili korzystać
bezpośrednio z języka HTML.
Zakłada się, że projektanci nie są programistami języka
Python. Autorzy systemu szablonów są przekonani, że
większość szablonów stron WWW piszą projektanci, a nie
programiści, więc nie należy zakładać znajomości języka
Python.
Szkielety tworzenia aplikacji
148
Filozofia i ograniczenia IV
System stara się zaspokoić sposób pracy małych zespołów , w
których to szablony są tworzące przez programistów języka
Python. Oferuje sposoby rozszerzenia składni systemu przez
pisanie czystego kodu Pythona.
Celem nie jest wymyślanie języka programowania. Celem jest
zapewnienie wystarczającej swobody przez dostarczenie pętli i
warunków, by możliwe było podejmowanie decyzji związanych
z prezentacją danych.
Szkielety tworzenia aplikacji
149
Podstawy systemu szablonów
Szablon Django to łańcuch tekstowy mający na celu odseparowanie
prezentacji dokumentu od jego danych. Szablon definiuje miejsca
wstawień danych oraz zawiera prostą logikę (znaczniki szablonu),
które określając sposób wyświetlania dokumentu. Najczęściej
szablony używa się do generowania kodu HTML, ale szablony
Django doskonale nadają się do generowania danych w dowolnym
formacie tekstowym.
Szkielety tworzenia aplikacji
150
Przykład szablonu I
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
Szkielety tworzenia aplikacji
151
Korzystanie z systemu szablonów I
Utwórz obiekt Template, przekazując treść szablonu jako
tekst.
Wywołaj metodę render() obiektu Template wraz z zestawem
zmiennych zwanym kontekstem. Wynikiem jest w pełni
zrenderowany kod ze wszystkimi zmiennymi i znacznikami
szablonowymi wyliczonymi i wstawionymi zgodnie z
zawartością kontekstu.
Szkielety tworzenia aplikacji
152
Korzystanie z systemu szablonów II
Kod:
>>> from django import template
>>> t = template.Template("Nazywam się {{ name }}.")
>>> c = template.Context({’name’: ’Adrian’})
>>> print t.render(c)
Nazywam się Adrian.
>>> c = template.Context({’name’: ’Fred’})
>>> print t.render(c)
Nazywam się Fred.
Najprostszym sposobem utworzenia obiektu typu Template jest
bezpośrednie użycie jego klasy. Klasa Template znajduje się w
module django.template. Konstruktor przyjmuje jeden argument,
którym jest nieprzetworzony kod szablonu.
Szkielety tworzenia aplikacji
153
Błędy szablonów
System zgłasza wyjątek TemplateSyntaxError dla każdego z
podanych niżej przypadków:
niepoprawnych znaczników,
niepoprawnych argumentów poprawnych znaczników,
błędnych filtrów,
niepoprawnych argumentów poprawnych filtrów,
złej składni szablonu,
niedomkniętych znaczników (dla znaczników wymagających
zamknięcia).
Szkielety tworzenia aplikacji
154
Filtry i znaczniki szablonów I
{% if %} analizuje zmienną i jeśli jej wartość odpowiada
wartości prawdy (czyli istnieje, nie jest pusta i nie jest
fałszem), system wyświetli wszystko między {% if %} i
{% endif %}. Oto przykład:
{% if today_is_weekend %}
<p>Ciesz się weekendem!</p>
{% else %}
<p>Do roboty!</p>
{% endif %}
{% for %} umożliwia przejście przez każdy element pewnej
sekwencji. Podobnie jak w Pythonie, stosowaną składnią jest
for X in Y. W każdym cyklu pętli system szablonów będzie
renderował wszystko, co znajdzie się między znacznikami
{% for %} i {% endfor %}.
Szkielety tworzenia aplikacji
155
Filtry i znaczniki szablonów II
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
{% ifequal %} umozliwia porównanie dwóch wartości
{% ifequal user currentuser %}
<h1>Witaj!</h1>
{% endifequal %}
Komentarze wstawiamy w znacznikach {# #}
Komentarze można również umieszczać pomiędzy tagami
{% comment %}Treść komentarza{% endcomment %}
Szkielety tworzenia aplikacji
156
Filtry i znaczniki szablonów III
Filtry to sposób na zmianę zawartości zmiennej przed jej
wyświetleniem (wykorzystuje się w tym celu znak pionowej
kreski)
zmiana zmiennej name za pomocą filtru lower
{{ name|lower }}
filtry da się łączyć w łańcuchy (wynik działania filtru jest
przekazywany do następnego w kolejności filtru)
{{ my_list|first|upper }}
filtry mogą również przyjmować parametry
{{ bio|truncatewords:"30" }}
Szkielety tworzenia aplikacji
157
Filtry i znaczniki szablonów IV
Ważniejsze filtry:
safe - zapobiega kodowaniu tagów HTML
add - dodaje do zmiennej podaną jako argument wartość
(zmienna|add:"liczba"),
cut - usuwa wszystkie wystąpienia podanego łańcucha w
zmiennej (zmienna|cut:"łańcuch"),
default - jeżeli zmienna może być interpretowana jako fałsz,
wykorzystuje się podaną jako argument wartość,
escape - zamienia < > oraz cudzysłowy na format Html,
first - zwraca pierwszy element z listy,
length - zwraca długość przekazywanego do niego elementu
(np. listy, łańcucha znaków),
linebreaks - zamienia przejścia do nowej linii na tagi p i br,
lower - zamienia wszystkie litery na małe,
Szkielety tworzenia aplikacji
158
Filtry i znaczniki szablonów V
pluralize - zwraca przyrostek jeżeli wartość nie jest równa 1
(domyślnie dodaje s)
Masz {{ n_m }} wiadomoś{{ n_m|pluralize:"ć,ci" }},
removetags - usuwa tagi X/HTML ze zmiennej (tagi są
podane jako argument oddzielone spacjami),
striptags - usuwa wszystkie tagi X/HTML,
truncatewords - przycina łańcuch do łańcucha zawierającego
określoną liczbę słów (wycięte słowa są zastępowane ...),
unordered_list - przerabia listę na listę li/ul,
upper - wszystkie litery zmieniane są na duże,
urlize - zamienia linki w zwykłym tekście na odnośniki, które
można kliknąć,
wordcount - zwraca liczbę słów,
wordwrap - łamie wiersze przy podanej liczbie znaków.
Szkielety tworzenia aplikacji
159
Dziedziczenie szablonów I
Dziedziczenie szablonów umożliwia tworzenia szkieletowych
szablonów, które zawierają wszystkie wspólne elementy tworzonej
aplikacji i definiują bloki które są przesłaniane przez pochodne
szablony.
Szablon bazowy base.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<title>
{% block title %}My amazing site{% endblock %}
</title>
</head>
Szkielety tworzenia aplikacji
160
Dziedziczenie szablonów II
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
Szkielety tworzenia aplikacji
161
Dziedziczenie szablonów III
Szablon pochodny:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
Szkielety tworzenia aplikacji
162
Korzystanie z szablonów w widokach I
Szablon z wykorzystaniem metod Pythona:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>Teraz jest %s.
</body></html>" % now
return HttpResponse(html)
Szkielety tworzenia aplikacji
163
Korzystanie z szablonów w widokach II
Szablon Django (Template):
from django.template import Template, Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now() t =
Template("<html><body>
Teraz jest {{ current_date }}.
</body></html>") html =
t.render(Context({’current_date’: now}))
return HttpResponse(html)
Szkielety tworzenia aplikacji
164
Korzystanie z szablonów w widokach III
Szablon z pliku:
from django.template import Template, Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
# Prosty sposób użycia szablonu z systemu plików.
fp = open(’/home/ja/templates/mytemplate.html’)
t = Template(fp.read())
fp.close()
html = t.render(Context({’current_date’: now}))
return HttpResponse(html)
Szkielety tworzenia aplikacji
165
Wczytywanie szablonów I
konfiguracja ścieżki szablonów w pliku settings.py
TEMPLATE_DIRS = (
’/home/ja/pracuj/templates’,
)
można również skorzystać z katalogów domyślnych templates
Szkielety tworzenia aplikacji
166
Wczytywanie szablonów II
zmiana pliku widoku:
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = get_template(’current_datetime.html’)
html = t.render(Context({’current_date’: now}))
return HttpResponse(html)
Szkielety tworzenia aplikacji
167
render_to_response()
Django zapewnia skrót, który pozwala wczytać szablon,
zrenderować go i zwrócić obiekt HTTPResponse - wszystko to w
jednym wierszu kodu.
from django.shortcuts
import render_to_response
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response(
’current_datetime.html’,
{’current_date’: now}
)
Szkielety tworzenia aplikacji
168
Model I
Model jest pojedynczym źródłem danych. Zawiera pola składowe i
informacje w jaki sposób składować dane. Najczęściej z każdym
modelem jest powiązana tabela bazy danych.
Każdy model jest podklasą klasy django.db.models.Model.
Każdy atrybut jest związany z odpowiednim polem tabeli.
Django dostarcza automatycznie wygenerowaneog API
pozwalającego na dostęp do bazy danych.
Szkielety tworzenia aplikacji
169
Model II
Przykład modelu
class Muzyk(models.Model):
imie = models.CharField(max_length=50)
nazwisko = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artysta = models.ForeignKey(Muzyk)
nazwa = models.CharField(max_length=100)
data_wydania = models.DateField()
liczba_gwiazdek = models.IntegerField()
Szkielety tworzenia aplikacji
170
Typy pól składowych I
AutoField
FilePathField
BigIntegerField
FloatField
BooleanField
ImageField
CharField
IntegerField
CommaSeparatedIntegerField
IPAddressField
DateField
NullBooleanField
DateTimeField
PositiveIntegerField
DecimalField
PositiveSmallIntegerField
EmailField
SlugField
FileField
SmallIntegerField
FileField
TextField
FieldFile
TimeField
URLField
Szkielety tworzenia aplikacji
171
Opcje pól składowych I
null - jeśli jest ustawione na True, Django umożliwi
przechowywanie wartości pustych jako NULL (wartość
domyślna False),
blank - jeżeli jest ustawione na True pole może być pominięte
w trakcie wprowadzania wartości (wartość domyślna False);
jest to wartość różna od null, null jest związane z relacyjnymi
bazami danych, natomiast blank jest związane z sposobem
walidacji,
choices - lista lub krotka zawierająca dwuelementowe krotki
używane do wyboru danych dla tego pola; jeśli jest ustawione
administrator może użyć listy rozwijanej zamiast
standardowych pól tekstowych, umożliwia ograniczenie wyboru
wartości.
Szkielety tworzenia aplikacji
172
Opcje pól składowych II
Pierwszym elementem w krotce jest wartość jaka będzie
zachowana w bazie danych, drugim elementem krotki jest
element jaki będzie wyświetlony w interfejsie administratora
lub w ModelChoiceField. Wyświetlana wartość pola
wybieralnego może być osiągnięta za pomocą metody
get_FOO_display() (FOO powinno być zastąpione nazwą
pola składowego). Na przykład:
from django.db import models
class Person(models.Model):
GCH = (
(u’M’, u’Mężczyzna’),
(u’K’, u’Kobieta’),
)
name = models.CharField(max_length=60)
gender = models.CharField(max_length=2, choices=GCH)
Szkielety tworzenia aplikacji
173
Opcje pól składowych III
>>> p = Person(name="Fred", gender="M")
>>> p.save()
>>> p.gender
u’M’
>>> p.get_gender_display()
u’Mężczyzna’
default - wartość domyślna pola,
help_text - dodatkowa pomoc wyświetlana dla pola w
interfejsie administracyjnym,
primary_key - jeśli jest ustawiona na True to pole jest
traktowane jako klucz główny modelu; gdy żadne pole nie jest
ustawione jako klucz główny, Django tworzy taki klucz w
sposób automatyczny,
unique - jeśli jest ustawiona na True dane pole musi być
unikalne dla całej tabeli.
Szkielety tworzenia aplikacji
174
Relacje pomiędzy modelami I
Relacje wiele do jednego - są realizowane za pomocą klasy
django.db.models.ForeignKey. Konstruktor klasy
ForeignKey wymagania podania klasy z którą podany model
jest powiązany.
class Producent(models.Model):
# ...
class Samochod(models.Model):
producent = models.ForeignKey(Producent)
# ...
Można tworzyć relacje rekurencyjne (obiekt z relacja wiele do
jednego do samego siebie - models.ForeignKey(’self’))
i relacje do modeli, które nie są jeszcze zdefiniowane
models.ForeignKey(’Producent’).
Szkielety tworzenia aplikacji
175
Relacje pomiędzy modelami II
Relacje wiele do wielu - są realizowane za pomocą klasy
ManyToManyField. Konstuktor klasy ManyToManyField
podania klasy z którą model jest powiązany
class Dodatek(models.Model):
# ...
class Pizza(models.Model):
# ...
dodatki = models.ManyToManyField(Topping)
Można tworzyć relacje rekurencyjne i relacje z modelami, które
jeszcze nie zostały zdefiniowane.
Nie ma znaczenia, który model posiada pole
ManyToManyField powinno być użyte w jednym wybranym
modelu.
Szkielety tworzenia aplikacji
176
Relacje pomiędzy modelami III
Możliwe jest również utworzenie klasy zarządzającej relacją
wiele do wielu dla bardziej skomplikowanych przypadków.
from models import ManyToManyField
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = ManyToManyField(Person, through=’Member’)
def __unicode__(self):
return self.name
Szkielety tworzenia aplikacji
177
Relacje pomiędzy modelami IV
class Member(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Relacja jeden do jednego - są realizowane za pomocą klasy
OneToOneField. Są najbardziej użyteczne dla kluczy głównych
obiektów, które są rozszerzane w jakiś sposób przez inny
obiekt. Konstruktor klasy OneToOneField wymaga podania
klasy z którą podany model jest powiązany.
Można tworzyć relacje rekurencyjne i relacje z modelami, które
jeszcze nie zostały zdefiniowane.
Szkielety tworzenia aplikacji
178
Klasa wewnętrzna Meta I
Django pozwala używać dodatkowych metainformacji o modelu, są
one definiowane z wykorzystaniem klasy wewnętrznej modelu o
nazwie Meta.
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name = "wół"
verbose_name_plural = "woły"
Szkielety tworzenia aplikacji
179
Klasa wewnętrzna Meta II
Najważniejszymi polami są:
db_table - nazwa tabeli (jeśli potrzebna jest nazwa różna od
standardowej),
order_with_respect_to - określa sortowanie względem
zależnego pola,
ordering - domyślny sposób porządkowania obiektów
permissions - określa dodatkowe (oprócz standardowych
add, delete, change) uprawnienia dla obiektów danego modelu,
verbose_name - czytelna dla człowieka nazwa pojedynczego
obiektu,
verbose_name_plural - czytelna dla człowieka nazwa wielu
obiektów.
Szkielety tworzenia aplikacji
180
Metody modeli I
full_clean(exclude=None) - wywołuje metody w kolejności
clean_fields(), clean() i validate_unique() zgłasza
wyjątek ValidationError jeśli, w którykolwiek z etapów
zakończy się błędem,
clean_fields(exclude=None) - metoda waliduje wszystkie
pola modelu (wywołuje w razie niepowodzenia wyjątek
ValidationError),
validate_unique(exclude=None) - metoda podobna w
działaniu do clean_fields() przy czym waliduje wszystkie
ograniczenia modelu jako całości zamiast pojedynczych pól,
clean() - metoda ta powinna zostać przesłonięta dla
wprowadzenia własnej walidacji i modyfikacji atrybutów
modelu
Szkielety tworzenia aplikacji
181
Metody modeli II
def clean(self):
if self.status == ’draft’ and self.pub_date is not None:
raise ValidationError(’Niedozwolone pole dla wersji roboczej’)
if self.status == ’published’ and self.pub_date is None:
self.pub_date = datetime.datetime.now()
save() - zapisuje obiekt do bazy danych, może być
przesłonięta,
autoinkrementacja kluczów głównych, przeprowadzona dopiero
po pierwszym użyciu metody save(),
właściwość pk - właściwość, która posiada każdy model
niezależnie od tego czy klucz główny został zdefiniowany
samodzielnie czy został wprowadzony przez Django, jest
aliasem do klucza głównego,
delete([using=DEFAULT_DB_ALIAS]) - powoduje wywołanie
komendy SQL DELETE, niszczy tylko obiekt w bazie danych,
można ją przesłonić w własnym modelu,
Szkielety tworzenia aplikacji
182
Metody modeli III
__unicode__() wywoływana za każdym razem, gdy
wywoływane jest z obiektem jako argumentem unicode().
Django używa unicode(obj) (lub związanej z nią str(obj)) w
wielu miejscach np. w interfejsie administracyjnym i jako
wartość wstawiana do szablonu, gdy konieczne jest
wyświetlenie zawartości obiektu.
get_absolute_url() powiadamia Django jak ma wyznaczać
adresy URL dla obiektów, jest użyteczne dla szablonów
def get_absolute_url(self):
return "/people/%i/" % self.id
Zamiast
<a href="/people/{{ obj.id }}/">{{ obj.name }}</a>
lepiej użyć:
<a href="{{ obj.get_absolute_url }}">{{ obj.name }}</a>
Szkielety tworzenia aplikacji
183
Metody modeli IV
get_FOO_display() - dostępna dla atrybutów wybieralnych,
dekorator permlink - pobiera nazwę wzorca URL i listę
pozycyjnych lub nazwanych argumentów i tworzy pełny,
poprawny adres URL.
(r’^people/(\d+)/$’, ’people.views.details’),
@models.permalink
def get_absolute_url(self):
return (’people.views.details’, [str(self.id)])
Szkielety tworzenia aplikacji
184
Metody modeli V
Podobnie:
(r’/archive/\
(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$’,
archive_view)
@models.permalink
def get_absolute_url(self):
return (’archive_view’, (), {
’year’: self.created.year,
’month’: self.created.strftime(’%m’),
’day’: self.created.strftime(’%d’)})
Szkielety tworzenia aplikacji
185
QuerySet I
Obiekty QuerySet są tworzone przez metody (all, filter,
exclude, get) klasy Manager w celu uzyskiwania obiektów z
bazy danych.
Obiekty te reprezentują kolekcje obiektów. Mogą zawierać
filtry, które zawężają wybór pod względem podanych
parametrów.
W terminologii SQL reprezentują instrukcje SELECT natomiast
filtry są związane z klauzulami takimi jak WHERE lub LIMIT.
Nie wykonują od razu zapytań, wykonują je tylko wtedy gdy
jest to wymgagane np. przy pierwszym przejściu przez
elementy objęte zapytaniem.
Szkielety tworzenia aplikacji
186
QuerySet II
>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name=’Foo’, tagline=’Bar’)
>>> b.objects
Traceback:
...
AttributeError: "Manager isn’t accessible via
Blog instances."
Ostatnia linijka kończy się błędem, gdyż obiekt managera jest
dostępny za pomocą klasy modelu a nie instancji modelu, wymusza
to odseparowanie operacji na tabeli od operacji na rekordzie.
Metody Managera:
Szkielety tworzenia aplikacji
187
QuerySet III
all() - zwraca QuerySet zawierający wszystkie obiekty z
tabeli
>>> all_entries = Entry.objects.all()
filter(**kwargs) - uzyskuje QuerySet, którego obiekty
spełniają podane jako argumenty kryterium;
Entry.objects.filter(pub_date__year=2006)
exclude(**kwargs) - uzyskuje QuerySet, którego obiekty nie
spełniają podane jako argumenty kryterium, można wywołania
tej metody i poprzedniej łączyć w łańcuchy wywołań;
Szkielety tworzenia aplikacji
188
QuerySet IV
>>>
...
...
...
...
...
...
Entry.objects.filter(
headline__startswith=’What’
).exclude(
pub_date__gte=datetime.now()
).filter(
pub_date__gte=datetime(2005, 1, 1)
)
get() - pozwala na uzyskiwanie pojedynczego obiektu jako
wyniku zapytania (tylko jednego!)
>>> one_entry = Entry.objects.get(pk=1)
Szkielety tworzenia aplikacji
189
Architektura aplikacji Qt
Podstawowa architektura Qt:
Niejawne współdzielenie obiektów
Model obiektu
Drzewa obiektów i własności obiektów
Sygnały i sloty
System zdarzeń
System metaobiektów
Szkielety tworzenia aplikacji
190
Niejawne współdzielenie obiektów I
Wiele klas Qt korzysta z współdzielenia zasobów w celu
minimalizacji operacji kopiowania.
Zapisana w ten sposób klasa zawiera wkaźnik do
współdzielonych danych i licznik odniesień.
Podczas tworzenia obiektu licznik odniesień jest ustawiany na
1, zwiększa się wraz z tworzeniem nowych obiektów
korzystających z współdzielonych danych natomiast zminiejsza
się gdy obiekt nie korzysta już z współdzielonych danych.
Współdzielone zasoby są niszczone gdy licznik odniesień
zmniejszy się do zera.
Szkielety tworzenia aplikacji
191
Niejawne współdzielenie obiektów II
Strategia ta jest efektywna przy przekazywaniu obiektów klas
jako argumentów wywołania funkcji, gdyż przekazywane są
jedynie wskażniki do danych (płytkie kopiowanie), kopiowanie
całości danych następuje jedynie wtedy, gdy funkcja zapisuje
wartości do danych (głębokie kopiowanie) - aby nastąpiło
automatycznie odłączenie obiektu od udostępnionych zasobów
licznik odniesień musi być większy niż jeden..
Podejście umożliwia również efektywniejsze korzystanie z
zasobów komputera, gdyż nie są niepotrzebnie kopiowane i
duplikowane zasoby.
Współdzielenie danych jest wykonywane niejawnie i nie musi
być obsługiwane przez programistę.
Szkielety tworzenia aplikacji
192
Model obiektu I
Qt dodaje do klas C++ następujące elementy:
mechanizm bezproblemowej komunikacji pomiędzy obiektami
za pomocą sygnałów i slotów,
mechanizm zdarzeń i filtrów zdarzeń,
możliwe do przeszukiwania i zaprojektowania właściwości
obiektów (property),
zależną od kontekstu translacje łańcuchów znaków użyteczną
do przygotowania różnych wersji językowych,
Szkielety tworzenia aplikacji
193
Model obiektu II
opartą na interwałach implementacje liczniki czasu (timer)
umożliwiające wykonywanie wielu zadań w opartym na
zdarzeniach graficznym interfejsie użytkownika,
hierarchiczne i możliwe do przeszukiwania drzewo obiektów
uwzględniające właścicieli obiektów,
wskaźniki (QPointer) automatycznie ustawiane na 0, gdy
obiekt na który wskazują zostaje zniszczony - pozwala to na
uniknięcie wiszących wskaźników,
dynamiczne rzutowanie działające poza granicami bibliotek.
Szkielety tworzenia aplikacji
194
Model obiektu III
Podstawowe klasy w modelu obiektu Qt
QMetaClassInfo - zawiera dodatkowe informacje o klasie.
QMetaEnum - zawiera metadane o typach wyliczeniowych.
QMetaMethod - zawiera metadane o funkcji składowej.
QMetaObject - zawiera metainformacje o obiektach Qt.
QMetaProperty - zawiera metadane o właściwościach.
QMetaType - zarządza typami w systemie metaobiektowym.
Szkielety tworzenia aplikacji
195
Model obiektu IV
QObject - klasa bazowa dla wszystkich obiektów Qt.
QObjectCleanupHandler - pozwala na obserwowanie cyklu
życiowego obiektów Qt.
QPointer - klasa szablonowa, która zapewnia bezpieczne
wskaźniki do obiektów Qt.
QSignalMapper - pakuje sygnały z zidentyfikowanymi
nadawcami.
QVariant - działa jako unia dla najbardziej popularnych typów
danych Qt.
Szkielety tworzenia aplikacji
196
Model obiektu V
void methodInformation(QObject* e)
{
const QMetaObject *mO = e->metaObject();
for(int i = mO->methodOffset();
i < mO->methodCount();++i)
{
QMetaMethod mMeth = mO->method(i);
std::cout << mMeth.methodType()
<< " " << mMeth.signature() << std::endl;
}
}
Szkielety tworzenia aplikacji
197
System metaobiektów I
System metaobiektowy jest oparty o:
klasę QObject będącą klasą bazową dla obiektów, które mogą
korzystać z systemu metaobiektów,
makro Q_OBJECT umieszczone wewnątrz deklaracji klasy,
które służy do włączenia cech metaobiektowych takich jak
właściwości, sygnały czy sloty,
narzędzie Meta-Object Compiler (moc), które wspomaga
każdą podklasę QObject kodem niezbędnym do implementacji
cech metaobiektów.
Szkielety tworzenia aplikacji
198
System metaobiektów II
Oprócz wspomagania komunikacji z wykorzystaniem sygnałów i
slotów metaobiekty wprowadzają dodatkowe właściwości takie jak QObject::metaObject(), QMetaObject::className(),
QObject::inherits(), QObject::tr() i QObject::trUtf8(),
QObject::setProperty() i QObject::property(),
QMetaObject::newInstance().
Możliwe jest także wykonywanie dynamicznego rzutowania przy
użyciu qobject_cast() klas z hierachii QObject. Funkcja
qobject_cast() działa podobnie jak dynamic_cast() z
standardowego C++ (dla wskaźników), nie wymaga jednak
wsparcia dla RTTI i działa dla kodu z bibliotek dynamicznych.
Szkielety tworzenia aplikacji
199
Drzewo obiektów I
Obiekty Qt są organizowane w hierachiczne drzewo obiektów podczas tworzenia obiektu klasy QObject z wykorzystaniem
rodzica (parent), jest on włączany do listy dzieci (children())
tego rodzica, gdy rodzic jest niszczony to również niszczone są
wszystkie jego dzieci.
QWidget dodatkowo roszerza relację rodzic-dziecko. Dziecko
jest wyświetlane w układzie współrzędnych rodzica i jest
dopasowywane do granic rodzica.
W sytuacji gdy obiekt jest niszczony w sposób niezależny, to
wówczas usuwa on odniesienie do siebie z rodzica.
Szkielety tworzenia aplikacji
200
Drzewo obiektów II
Z reguły obiekty typu QObject powinny być tworzone na
stercie (operator new), gdyż umożliwia to niszczenie obiektów
drzewa w dowolnym porządku. Kiedy QObject w drzewie
zostanie usunięty, jeśli ma rodzica, destruktor automatycznie
usuwa odniesienie do tego obiektu z obiektu jego rodzica. Jeśli
obiekt ma dzieci, destruktor automatycznie usuwa każde
dziecko.
Obiekty tworzone na stosie wymagają większej uwagi, gdyż
konieczne jest sprawdzenie kolejności tworzenia obiektów.
int main(int argc, char** argv)
{
QWidget window;
QPushButton quit("Quit", &window);
...
}
Szkielety tworzenia aplikacji
201
Drzewo obiektów III
int main()
{
QPushButton quit("Quit");
QWidget window;
quit.setParent(&window);
...
}
Pierwszy przykład w porządku - obiekt quit usunie siebie z listy
dzieci window natomiast w drugim problemem jest to, że
nastąpi próba zniszczenia obiektu automatycznego z obiektu
window.
Szkielety tworzenia aplikacji
202
System zdarzeń I
Zdarzenia są obiektami wyprowadzonymi z abstrakcyjnej klasy
QEvent i reprezentują rzeczy, które mogą się zdarzyć w
aplikacji lub jako wynik jakiejś zewnętrznej operacji, która
powinna być znana przez program.
Zdarzenia mogą być wysyłane i obsługiwane przez dowolną
instancję podklasy QObject, ale najbardziej użyteczne są dla
widgetów.
Gdy zdarzenie się pojawia Qt tworzy obiekt odpowiedniego
zdarzenia i dostarcza go do właściwej instancji QObject
poprzez wywołanie funkcji event(). Funkcja ta nie przetwarza
zdarzenia, lecz przekazuje go do odpowiedniej funkcji jego
obsługi.
Szkielety tworzenia aplikacji
203
System zdarzeń II
Normalny sposób obsługi zdarzenia uwzględnia wywołanie
odpowiedniej funkcji wirtualnej. Jeśli nie jest wykonywana w
funkcji obsługi zdarzenia cała praca można przekazać
sterowanie do funkcji z klasy nadrzędnej.
void MyCheckBox::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
// ...
} else {
// Przekazanie do funkcji z klasy bazowej.
QCheckBox::mousePressEvent(event);
}
}
Szkielety tworzenia aplikacji
204
System zdarzeń III
Zdarza się, że nie taka funkcja zdarzenia nie jest dostępna lub
nie jest ona wystarczająca.
Najbardziej typowy przykład to obsługa klawisza tabulacji.
Normalnie, naciśnięcie klawisza Tab powoduje przeniesienie
ogniska wejściowego klawiatury do następnego widgetu,
niektóre widgety mogą jednak wymagać klawisza Tab dla
własnych celów.
Obiekty te mogą reimplementować funkcję QObject::event() ogólny uchwyt dla zdarzeń.
Szkielety tworzenia aplikacji
205
System zdarzeń IV
bool MyWidget::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_Tab) {
// Specjalny sposób traktowania tabulacji
return true;
}
} else if (event->type() == MyEvent) {
MyEvent *mE = static_cast<MyEvent *>(event);
// obsługa własnego zdarzenie
return true;
}
return QWidget::event(event);
}
Szkielety tworzenia aplikacji
206
System zdarzeń V
Czasami obiekt musi możliwość zajrzenia i być może
przechwycenia, zdarzeń, które są skierowane do innego obiektu.
Funkcja QObject::installEventFilter() umożliwia ustanowienie
filtru zdarzeń, który powoduje przekazanie zdarzenia do jego
funkcji QObject::eventFilter(). Filtr zdarzeń otrzymuje do
przetworzenia zdarzenie jeszcze przed obiektem docelowym, co
pozwala na sprawdzenie i ewentualne, jeśli istnieje taka
potrzeba, odrzucenie zdarzenia. Istniejący filtr zdarzeń można
usunąć za pomocą funkcji QObject::removeEventFilter().
Podczas wywołania funkcji eventFilter() można zaakceptować
lub odrzucić zdarzenie oraz zezwolić lub odmówić dalszego
przetwarzania zdarzenia. Jeśli wszystkie filtry zdarzeń
umożliwiają dalsze przetwarzania zdarzenia (poprzez zwracanie
false), to zdarzenie jest wysyłane do obiektu docelowego. Jeśli
jeden z nich zatrzymuje przetwarzanie (zwracając true) cel i
inne filtry nie są w ogóle w stanie zobaczyć to zdarzenie.
Szkielety tworzenia aplikacji
207
System zdarzeń VI
bool FilterObj::eventFilter(QObject *o, QEvent *e)
{
if (o == target && e->type() == QEvent::KeyPress) {
QKeyEvent *kEv = static_cast<QKeyEvent *>(e);
if (kEv->key() == Qt::Key_Tab) {
// Specjalny sposób przetwarzania Tab
return true;
} else
return false;
}
return false;
}
Szkielety tworzenia aplikacji
208
System zdarzeń VII
Możliwe jest również filtrowanie wszystkich zdarzeń dla całej
aplikacji poprzez zainstalowanie filtra zdarzeń na obiekcie
QApplication lub QCoreApplication. Te globalne filtry zdarzeń
są wywoływane przed filtrami poszczególnych obiektów.
Wiele aplikacji może tworzyć i wysyłać własne zdarzenia.
Można wysłać zdarzenia w dokładnie w ten sam sposób jak w
pętli komunikatów Qt poprzez tworzenie odpowiednich
obiektów zdarzeń i wysyłania ich za pomocą
QCoreApplication::sendEvent() i
QCoreApplication::postEvent().
Funkcja sendEvent() przetwarza zdarzenie natychmiast. Kiedy
kończy działanie, filtr zdarzenia lub sam obiekt docelowy
przetwarza od razu zdarzenie.
Szkielety tworzenia aplikacji
209
System zdarzeń VIII
Funkcja postEvent() wstawia zdarzenie w kolejce do
późniejszego przesłania. Następnym razem, gdy jest
wywoływana główna pętla zdarzeń Qt wysyła wszystkie
zdarzenia z kolejki z wykonaniem pewnych optymalizacji. Na
przykład, jeśli istnieje kilka zdarzeń zmiany rozmiaru, są one
łączone w jedno wywołanie. To samo dotyczy się
odmalowywania obiektu.
Utworzenie zdarzenia o niestandardowym typie wymaga
określenia numeru zdarzenia, który musi być większy niż
QEvent::User, a może także wymagać utworzenia podklasy
QEvent w celu przekazania szczegółowych informacji na temat
tego niestandardowego zdarzenia.
Szkielety tworzenia aplikacji
210
Zarządzanie wielkością kontrolki I
Klasa QSizePolicy:
Jest atrybutem managera układu, opisuje pionowe i poziome
zarządzanie rozmiarami kontrolki.
Wyraża wymagania widgetu odnośnie zmiany jego rozmiaru i
opisuje jak widget ma być traktowany przez manager układu.
Zawiera dwie niezależne wartości QSizePolicy i dwa
współczynniki rozsciągania opisujące zarządzanie wielkością
widgetu w pionie i w poziomie. Ponadto zawiera również flagę
PolicyFlag wskazującą czy wysokość i szerokość widgetu są
powiązane z jego preferowaną wielkością.
Szkielety tworzenia aplikacji
211
Zarządzanie wielkością kontrolki II
Flagi QSizePolicy::PolicyFlag:
QSizePolicy::GrowFlag - widget może powiększać swój
rozmiar poza rozmiar zalecany jeśli jest to konieczne.
QSizePolicy::ExpandFlag - widget zajmuje największą
możliwą przestrzeń.
QSizePolicy::ShrinkFlag - widget może zmniejszać swój
rozmiar poniżej rozmiaru zalecanego jeśli jest to konieczne.
QSizePolicy::IgnoreFlag - rozmiar zalecany jest
ignorowany, widget zajmuje największą możliwą przestrzeń.
Szkielety tworzenia aplikacji
212
Zarządzanie wielkością kontrolki III
Rodzaje zarządzania wielkością:
QSizePolicy::Fixed(0) - rozmiar zalecany jest jedynym
możliwym
QSizePolicy::Minimum (GrowFlag)
QSizePolicy::Maximum (ShrinkFlag)
QSizePolicy::Preferred (GrowFlag | ShrinkFlag)
QSizePolicy::Expanding (GrowFlag | ShrinkFlag | ExpandFlag)
QSizePolicy::MinimumExpanding (GrowFlag | ExpandFlag)
QSizePolicy::Ignored (ShrinkFlag | GrowFlag | IgnoreFlag)
Szkielety tworzenia aplikacji
213
Zarządzanie wielkością kontrolki I
Klasa QSizePolicy:
Jest atrybutem managera układu, opisuje pionowe i poziome
zarządzanie rozmiarami kontrolki.
Wyraża wymagania widgetu odnośnie zmiany jego rozmiaru i
opisuje jak widget ma być traktowany przez manager układu.
Zawiera dwie niezależne wartości QSizePolicy i dwa
współczynniki rozsciągania opisujące zarządzanie wielkością
widgetu w pionie i w poziomie. Ponadto zawiera również flagę
PolicyFlag wskazującą czy wysokość i szerokość widgetu są
powiązane z jego preferowaną wielkością.
Szkielety tworzenia aplikacji
214
Zarządzanie wielkością kontrolki II
Flagi QSizePolicy::PolicyFlag:
QSizePolicy::GrowFlag - widget może powiększać swój
rozmiar poza rozmiar zalecany jeśli jest to konieczne.
QSizePolicy::ExpandFlag - widget zajmuje największą
możliwą przestrzeń.
QSizePolicy::ShrinkFlag - widget może zmniejszać swój
rozmiar poniżej rozmiaru zalecanego jeśli jest to konieczne.
QSizePolicy::IgnoreFlag - rozmiar zalecany jest
ignorowany, widget zajmuje największą możliwą przestrzeń.
Szkielety tworzenia aplikacji
215
Zarządzanie wielkością kontrolki III
Rodzaje zarządzania wielkością:
QSizePolicy::Fixed(0) - rozmiar zalecany jest jedynym
możliwym
QSizePolicy::Minimum (GrowFlag)
QSizePolicy::Maximum (ShrinkFlag)
QSizePolicy::Preferred (GrowFlag | ShrinkFlag)
QSizePolicy::Expanding (GrowFlag | ShrinkFlag | ExpandFlag)
QSizePolicy::MinimumExpanding (GrowFlag | ExpandFlag)
QSizePolicy::Ignored (ShrinkFlag | GrowFlag | IgnoreFlag)
Szkielety tworzenia aplikacji
216
Podstawowe pojęcia
Wielobieżność (ang. reentrant) - Klasa jest wielobieżna jeśli
jest bezpieczne używanie jej instancji z więcej niż jednego
wątku, pod warunkiem, że najwyżej jeden wątek ma dostęp do
tej samej instancji klasy w tym samym czasie. Funkcja jest
wielobieżna jeśli jest bezpieczne wywoływanie jej z więcej niż
jednego wątku w tym samym czasie, pod warunkiem, że każde
jej wywołanie odnosi się do unikalnych danych.
Bezpieczeństwo ze względu na wątki (ang. thread safe) - Klasa
jest bezpieczna ze względu na wątki jeśli możliwe jest
bezpieczne korzystanie z jej instancji w więcej niż jednym
wątku. Funkcja jest bezpieczna ze względu na wątki jeśli jest
bezpieczne wywoływanie jej w więcej niż jednym wątku w tym
samem czasie nawet jeśli wywołanie odnosi się do
współdzielonych danych.
Szkielety tworzenia aplikacji
217
Przykłady wielobieżności i bezpieczeństwa I
class Licznik
{
public:
Licznik():n(0) {}
void increment() { ++n; }
void decrement() { --n; }
int value() const { return n; }
private:
int n;
};
Szkielety tworzenia aplikacji
218
Przykłady wielobieżności i bezpieczeństwa II
class Licznik
{
public:
Licznik():n(0) {}
void increment() {QMutexLocker lock(&mut); ++n;}
void decrement() {QMutexLocker lock(&mut); --n; }
int value() const {QMutexLocker lock(&mut); return n;}
private:
mutable QMutex mut;
int n;
};
Szkielety tworzenia aplikacji
219
QThread I
QThread
Klasa dostarcza niskopoziomowego API wspierającego pracę na
wątkach.
Obiekt tej klasy (podklasy) reprezentuje pojedynczy wątek,
współdzieli on dane z innymi wątkami uruchomionymi w tym
samym procesie, ale jest uruchomiony oddzielnie.
Ukrywa wszystkie zależne od konkretnego systemu
operacyjnego szczegóły implementacyjne.
Każdy wątek posiada własną pętlę komunikatów. Umożliwia to
wymianę informacji pomiędzy wątkami z wykorzystaniem
mechanizmu sygnałów i slotów.
Szkielety tworzenia aplikacji
220
QThread II
class MyThread : public QThread {
protected:
void run() {
/* implementacja */
}
};
MyThread *t = new MyThread;
t->start();
Szkielety tworzenia aplikacji
221
QThread III
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
/* Implementacja */
}
};
QThread *thread = new QThread;
Worker *worker = new Worker;
//Wskaźnik obj jest wyzwalaczem powodującym start zadania
connect(obj, SIGNAL(startWork()), worker, SLOT(doWork()));
worker->moveToThread(thread);
thread->start();
Szkielety tworzenia aplikacji
222
QRunnable i QThreadPool I
QRunnable jest lekką, abstrakcyjną klasą, która może być
użyta do rozopoczynania zadań w innym wątku w postaci
"uruchom i zapomnij".
W celu osiągnięcia tych zadań dziedziczy się po klasie
QRunnable i implementuje czysto abstrakcyjną metodę run():
class MyTask : public QRunnable {
public:
void run() {
/* Implementacja */
}
};
Szkielety tworzenia aplikacji
223
QRunnable i QThreadPool II
W celu rzeczywistego uruchomienia obiektu QRunnable używa
się klasy QThreadPool, która zarządza pulą wątków. Poprze
wywołanie QThreadPool::start(runnable) umieszcza się obiekt
QRunnable w kolejce uruchomionych wątków QThreadPool.
Tak szybko jak tylko wątek staje się dostępny, obiekty
QRunnable są zbierane i uruchomiene do takiego wątku.
Każda aplikacja Qt posiada globalną pulę wątków dostępną
poprzez wywołanie QThreadPool::globalInstance(), ale zawsze
można utworzyć własną prywatną instancję QThreadPool i
zarządzać nią jawnie.
QRunnable nie jest podklasą QObject dlatego też nie ma
wbudowanej komunikacji z innymi komponentami, dlatego
wymagane jest ręczna obsługa takiego kodu przy użyciu
niskopoziomowych mechanizmów wątków (jak strzeżona przez
muteksy kolejka dla zbierania wyników).
Szkielety tworzenia aplikacji
224
QConcurrent I
QtConcurrent jest wysokopozimowym API zbudowanym na
szczycie QThreadPool, przydatnym do wykonywania zadań z
użyciem popularnych modeli obliczeń równoległych:
mapowanie, redukcja i filtrowanie
Oferuje także metodę QtConcurrent::run (), którą można
wykorzystać do łatwego uruchomienia funkcji w innym wątku.
W przeciwieństwie do QThread i QRunnable, QtConcurrent nie
wymaga stosowania niskopoziomowych mechanizmów
synchronizacji.
Szkielety tworzenia aplikacji
225
Mechanizmy bezpiecznego synchronizowania wątków I
QMutex i QMutexLocker - służą do zablokowania dostępu do
pewnej sekcji kodu, sekcji krytycznej
QReadWriteLock - umożliwia blokowanie obiektów do
zapisu/odczytu
QSemaphore - umożliwia tworzenie semaforów (uogólnienie
muteksów)
QWaitCondition - wprowadza zmienne, które umożliwiają
synchronizację wątków
Szkielety tworzenia aplikacji
226
Sygnały i sloty pomiędzy wątkami I
Qt oferuje mechanizm wysyłania zdarzenia w kolejce
komunikatów wątku, natomiast obsługa zdarzenia jest
wykonywana w odpowiedniej przeznaczonej do tego celu
metodzie.
Mechanizm ten jest zbudowany za pomocą introspekcji metod
realizowanej przez moc, dlatego tylko sygnały, sloty i metody
oznaczone makrem Q_INVOKABLE mogą być wywoływane z
innych wątków.
Szkielety tworzenia aplikacji
227
Sygnały i sloty pomiędzy wątkami II
Typy połączeń:
bezpośrednie - oznacza, że slot jest zawsze wywoływany
bezpośrednio przez wątek emitowanego sygnału,
kolejkowane - oznacza, że zdarzenie jest zapisane w kolejce
zdarzeń wątku odbiorcy, które będą zabierane przez pętlę
komunikatów i wysyłane do gniazd jakiś czas później,
kolejkowane blokowane - połączenie jest realizowane jak w
połączeniu kolejkowanym, ale blokuje wątek nadawcy, aż do
chwili, gdy slot zakończy działanie, powinno być używane
jedynie wtedy, gdy nadawca i odbiorca są w innych wątkach,
automatyczne (domyślnie) - oznacza, że jeśli wątek odbiorcy w
tym samym bieżącym wątku to używane jest bezpośrednie
połączenie, w przeciwnym przypadku używane jest kolejkowane
połączenie.
Szkielety tworzenia aplikacji
228
System pluginów
Qt dostarcza dwóch API do tworzenia pluginów:
Wysokopoziomowego API do tworzenia pluginów dla biblioteki
Qt np.: sterowników bazy danych (QSqlDriverPlugin),
kodeków tekstowych (QTextCodecPlugin), obsługi
dodatkowych formatów obrazu (QImageIOPlugin), własnych
stylów (QStylePlugin).
Implementacja polega na zapewnieniu klasy dziedziczącej po
jednej z klas, dostarczeniu odpowiednich metod i dodaniu
makra.
Są przechowywane w standardowych katalogach Qt
Niskopoziomowego API przeznaczonego do rozszerzenia
aplikacji korzystających z biblioteki Qt.
Szkielety tworzenia aplikacji
229
Niskopoziomowe API I
Utworzenia aplikacji, która będzie mogła być rozszerzana za
pomocą pluginów wymaga następujących czynności:
1
Zdefiniowanie zbioru interfejsów (klas z jedynie czysto
wirtualnymi funkcjami - poza destruktorem) używanych do
późniejszej implementacji pluginów.
2
Użycia w kodzie makra Q_DECLARE_INTERFACE() w celu
poinformowania systemu metaobiektowego Qt o interfejsie.
3
Użycia obiektu klasy QPluginLoader do załadowania pluginu.
4
Przetestowania za pomocą qobject_cast() czy dany plugin
implementuje określony interfejs.
Szkielety tworzenia aplikacji
230
Niskopoziomowe API II
Tworzenie pluginu wymaga wykonania następujących kroków:
1
Zdefiniowanie klasy pluginu dziedziczącej po QObject i z klasy
zdefiniowanej wcześniej klasy interfejsu jaki ma zapewniać.
2
Użycie w kodzie makra Q_INTERFACES() w celu
poinformowania systemu metaobiektów biblioteki Qt o
implementowanym interfejsie.
3
Wyeksportowanie pluginu przy pomocy makra
Q_EXPORT_PLUGIN2().
4
Budowa pluginu przy pomocą odpowiedniego pliku .pro.
Szkielety tworzenia aplikacji
231
Definicja interfejsu dla pluginów
#ifndef SYNTAXHIGHLIGHTERPLUGIN_H
#define SYNTAXHIGHLIGHTERPLUGIN_H
class QStringList;
class QSyntaxHighlighter;
class SyntaxHighlighterPluginInterface
{
public:
virtual ~SyntaxHighlighterPluginInterface(){}
virtual QSyntaxHighlighter* getSyntaxHighlighter() = 0;
virtual QStringList getFileExtensions() = 0;
};
Q_DECLARE_INTERFACE(SyntaxHighlighterPluginInterface,
"com.sztap.SyntaxHighlighterPluginInterface/1.0")
#endif // SYNTAXHIGHLIGHTERPLUGIN_H
Szkielety tworzenia aplikacji
232
Implementacja interfejsu dla pluginów
#ifndef STYLEPLUGIN_H
#define STYLEPLUGIN_H
#include <QObject>
#include <syntaxhighlighterplugin.h>
class StylePlugin : public QObject, public SyntaxHighlighterPluginInterface
{
Q_OBJECT
Q_INTERFACES(SyntaxHighlighterPluginInterface)
public:
QSyntaxHighlighter* getSyntaxHighlighter();
QStringList getFileExtensions();
};
#endif // STYLEPLUGIN_H
Szkielety tworzenia aplikacji
233
Ładowanie pluginów
void MainWindow::loadPlugins()
{
QDir pluginsDir = directoryOf("plugins");
foreach(QString fileName, pluginsDir.entryList(QDir::Files))
{
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
if(SyntaxHighlighterPluginInterface *interface =
qobject_cast<SyntaxHighlighterPluginInterface*>(loader.instance()))
{
foreach(QString fileExt, interface->getFileExtensions())
fileExtMap[fileExt] = interface;
}
}
}
Szkielety tworzenia aplikacji
234
Modele-Widoki w Qt
Szkielety tworzenia aplikacji
235
Model I
Wszystkie modele Qt są oparte o klasę QAbstractItemModel.
Definuje ona interfejs, który jest używany przez widoki i
delegatów do dostępu do danych.
Dane nie są przechowywane bezpośrednio przez model, są
gromadzone w osobnych strukturach takich jak pliki, bazy
danych.
Klasa QAbstractItemModel dostarcza interfejsu, który jest
wystarczający elastyczny do obsługi tabel, list i drzew.
Często wygodniej jest posłużyć się do implementacji modeli
obsługujących tylko listy i tabele klas dostarczających
domyślnej implementacji dla niektórych metod - klas
QAbstractListModel i QAbstractTableModel
Szkielety tworzenia aplikacji
236
Model II
Qt dostarcza kilku wbudowanych modeli do obsługi danych:
QStringListModel jest używany do przechowywania prostych
list elementów typów QString.
QStandardItemModel zarządza bardziej skomplikowanymi
strukturami drzewiastymi elementów, które mogą zawierać
określone dane.
QFileSystemModel przechowuje informacje o plikach i
katalogach w lokalnym systemie plików.
QSqlQueryModel, QSqlTableModel i
QSqlRelationalTableModel są używane do dostępu do bazy
danych przy użyciu konwencji modeli/widoków.
Szkielety tworzenia aplikacji
237
Model III
Szkielety tworzenia aplikacji
238
Implementacja własnych modeli I
1
2
Dziedziczenie po jednej z klas QAbstractItemModel,
QAbstractListModel lub QAbstractTableModel.
Implementacja w zależności od zamierzonego efektu metod:
columnCount() - liczba kolumn,
data() - zwraca danych pod określonym indeksem i określoną
rolą,
index() - zwraca indeks elementu z określonego wiersza,
kolumny i rodzica,
parent() - zwraca jeśli istnieje indeks rodzica określonego
elementu,
flags() - powiadamia widok o tym co może zrobić z
elementem modelu (np. edycja, wybór),
rowCount() - liczba wierszy danych.
Szkielety tworzenia aplikacji
239
Widok I
Widoki są odpowiedzialne za otrzymywanie danych z modeli i
prezentowanie ich dla użytkownika.
Mogą prezentować dane w sposób niezależny od modelu i
struktur będących podstawą przechowywania danych.
Oddzielenie treści i prezentacji uzyskuje się porzez
zastosowanie standardowego interfejsu dla modelu
dostarczanego przez QAbstractItemModel, standardowy
interfejsu widoku dostarczanego przez QAbstractItemView i
wykorzystanie indeksów do modelu, które reprezentują
elementy danych w sposób ogólny.
Zazwyczaj zarządzają całymi danymi otrzymanymi z modelu.
Widoki mogą dostarczać sposobów edycji elementów
samodzielnie lub za pośrednictwem delegatów.
Szkielety tworzenia aplikacji
240
Widok II
Widoki obsługują również nawigację pomiędzy elementami i
kilka aspektów dotyczących sposobów wyboru (mogą np.
śledzić wybrane przez użytkownika elementy i wyświetlać je w
jednym lub wielu widokach) elementów.
Niektóre widoki (QTableView, QTreeView) dostarczają
nagłówków, które również są implementowane jako widoki
(QHeaderView).
Szkielety tworzenia aplikacji
241
Delegaty I
Delegaty są dostarczane w celu uzyskania dodatkowej
elastyczności przy edycji i wyświetlaniu danych.
Standardowy interfejs dla delegatów jest zdefiniowany w klasie
QAbstractItemDelegate.
Delegaci są w stanie renderować swoją zawartość poprzez
implementację funkcji paint() (odrysowanie elementu) i
sizeHint() (podpowiedź dla systemu Qt o najlepszym
rozmiarze elementu). W przypadku prostych opartych na
widgetach delegatów można skorzystać również z klasy
QItemDelegate, która dostarcza domyślnych implementacji
tych funkcji.
Szkielety tworzenia aplikacji
242
Delegaty II
Edytory dla delegatów mogą być realizowane za pomocą
widgetów, można również obsługiwać zdarzenia bezpośrednio.
Dostarczenie edytora wymaga przeimplementowania metod:
createEditor() - tworzenie kontrolki edycyjnej i instalacja
filtra zdarzeń,
setEditorData() - inicjowanie edytora za pomocą wartości
uzyskanych z modelu,
setModelData() - ustawianie wartości elementu modelu za
pomocą wartości uzyskanej z edytora,
updateEditorGeometry() - odświeżanie geometrii edytora.
Szkielety tworzenia aplikacji
243
Wykorzystane materiały:
Wykłady dr Olgi Siedleckiej-Lamch
http://djangobookpl.rafaljonca.org
http://www.djangobook.com/en/2.0/
http://django.pl
https://docs.djangoproject.com
http://qt-project.org/doc/qt-4.8/
http://qt-project.org/wiki/Threads_Events_QObjects
http://qt-project.org/doc/qt-4.8/model-viewprogramming.html
M. Summerfield - Advanced Qt Programming: Creating Great
Software with C++ and Qt 4 - Prentice Hall 2010
J. Forcier, P. Bissex, W. Chun - Python i Django:
Programowanie aplikacji webowych - Helion 2009
M. Lutz - Learning Python - O’Reilly 2009
Praca zbiorowa - Python. Od podstaw - Helion 2006
Szkielety tworzenia aplikacji
244

Podobne dokumenty