Obsługa baz danych w Django nie wymaga znajomości SQL. Będziemy pracować wyłącznie z obiektami w Pythonie.
Wybór SZBD Tworzenie tabel Wykorzystanie bazy danych na stronie
Musimy poinformować serwer jaki SZBD (SZBD = System Zarządzania Bazą Danych) chcemy używać. W tym celu edytujemy plik settings.py: zmieniamy wartość zmiennej DATABASES, będącej słownikiem słowników, obowiązkowy jest tylko opis domyślnej bazy ('default'):
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'rezerwacje' #zbieżność nazwy projektu i bazy danych jest nieistotna } }
Konieczne jest także zarejestrowanie tworzonej właśnie aplikacji:
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'pensjonat.bookings' )
Jeżeli wybierzemy inny SZBD, to słownik będzie musiał zawierać dodatkowe informacje: USER, PASSWORD, HOST, PORT,...
Żeby baza danych została utworzona i powiązana z projektem musimy wpisać polecenie:
python manage.py syncdbPolecenie to będzie konieczne również po dodaniu nowej tabeli.
Po pierwszym poleceniu syncdb zostanie utworzona nowa baza danych, w niej Django utworzy kilka tabel związanych z użytkownikami,
autoryzacją, zarządzaniem sesjami, itp. Zaproponuje również, by dopisać administratora (superuser w terminologii Django).
Spis treści
from django.db import models class Apartment(models.Model): bedrooms = models.SmallIntegerField() beds = models.SmallIntegerField() kitchenette = models.BooleanField() name = models.CharField(max_length=80,unique=True) pathToPicture = models.CharField(max_length=80)Wygenerowany przez Django kod SQL tworzący tabelę możemy obejrzeć wpisując polecenie:
python manage.py sql bookings
BEGIN; CREATE TABLE "bookings_apartment" ( "id" integer NOT NULL PRIMARY KEY, "bedrooms" smallint NOT NULL, "beds" smallint NOT NULL, "kitchenette" bool NOT NULL, "name" varchar(80) NOT NULL UNIQUE, "pathToPicture" varchar(80) NOT NULL ) ; COMMIT;Nazwa tabeli różni się nieco od nazwy klasy. Do tworzonej tabeli zostało dodane pole id tworzące klucz główny. Wszystkie pola mają klauzulę NOT NULL, jest to ustawienie domyślne dla wszytkich typów pól (z wyjątkiem NullBooleanField). Pole dopuszczające wartość null możemy utworzyc tak:
test = models.SmallIntegerField(null=True)Listę dostępnych opcji pól można znaleźć tutaj.
W Django nie wygodnego narzędzia do zmiany struktury tabel (ALTER TABLE ...). Dopisanie (usunięcie) kolumn w pliku models.py i wpisanie polecenia
python manage.py syncdbnie zmieni struktury tabel. Jeżeli tabele nie zawierają jeszcze danych, to strukturę tabel można zmienić poleceniem:
python manage.py reset nazwa_aplikacjiPolecenie to wygeneruje polecenia SQL DROP TABLE ... i CREATE TABLE ....
Django dostarcza wygodnego narzędzia do modyfikacji zawartości utworzonej bazy danych (dodawanie, modyfikacja i usuwanie rekordów, przeglądanie tabel). Wpisujemy polecenie:
python manage.py shellUruchamia ono tekstową konsolę Pythona w trochę niestandardowy sposób, do zmiennej sys.path zawierającej listę katalogów przeszukiwanych po poleceniu importu, zostaje dodany katalog tworzonej aplikacji. Możemy zatem wpisać polecenie:
from bookings.models import *Utworzenie obiektu i próba jego dopisania do tabeli:
a = Apartment() a.save() => ... IntegrityError: bookings_apartment.bedrooms may not be NULLDopisanie nie powiodło się, bo wartość pola bedrooms wynosi NULL. (Wartość pozostałych pól, z wyjątkiem pola id, również wynosi NULL.)
Kolejna próba:
a = Apartment(bedrooms=2,beds=6,kichenette=True,name="nr 13",pathToPicture="") print a.id => None a.save() print a.id => 1 Apartment.objects.count() => 1 a.delete() Apartment.objects.count() => 0Wartość polu id nadaje SZBD podczas dopisywania rekordu, SZBD gwarantuje również jednoznaczność tego pola. Pełną listę metod generujących zapytania do bazy danych można znaleźć tutaj.
Interaktywna praca z tabelami będzie znacznie wygodniejsza, jeśli rozbudujemy definicje klasy.
from django.db import models class Apartment(models.Model): bedrooms = models.SmallIntegerField() beds = models.SmallIntegerField() kitchenette = models.BooleanField() name = models.CharField(max_length=80,unique=True) pathToPicture = models.CharField(max_length=80) def setFields(self,bedrooms,beds,name,kitchenette=True,pathToPicture=""): self.bedrooms = bedrooms self.beds = beds self.kitchenette = kitchenette self.name = name.strip() self.pathToPicture = pathToPicture.strip() def __str__(self): s = "Apartament: "+self.name+" (id="+str(self.id)+")\n" s+="Sypialnie: "+str(self.bedrooms)+"\n" s+="Miejsca: "+str(self.beds)+"\n" s+="Aneks kuchenny: "+("tak" if self.kitchenette else "nie")+"\n" return sMetoda strip obcina białe znaki z lewej i z prawej strony. Wykorzystanie dopisanych metod:
a = Apartment() a.setFields(2,6,"nr 7") a.save() b = Apartment() b.setFields(1,3,"nr 2") b.save() Apartment.objects.count() => 2 for a in Apartment.objects.all(): print a => Apartament: nr 7 (id=1) Sypialnie: 2 Miejsca: 6 Aneks kuchenny: tak Apartament: nr 2 (id=2) Sypialnie: 1 Miejsca: 3 Aneks kuchenny: tak Apartment.objects.get(id=1).delete() for a in Apartment.objects.all(): print a => Apartament: nr 2 (id=2) Sypialnie: 1 Miejsca: 3 Aneks kuchenny: takModyfikację rekordu polegająca na zmianie wartości pola (pól) innego niż id można uzyskać tak:
a = Apartment.objects.get(id=2) a.beds = 2 a.save() for a in Apartment.objects.all(): print a => Apartament: nr 2 (id=2) Sypialnie: 1 Miejsca: 2 Aneks kuchenny: takWywołanie metody save() na rzecz obiektu, który już jest w bazie danych (ma nadany id) jest wykonaniem polecenia UPDATE ..., wywołanie tej metody na rzecz nowego obiektu jest wykonamiem polecenia INSERT ....
# _*_ coding: utf-8 _*_ from django.http import HttpResponse from django.template.loader import get_template from django.template import RequestContext from bookings.models import Apartment def main_page(request): template = get_template("main_page.html") apartments = Apartment.objects.all() variables = RequestContext(request,{'podpis':'Widok od strony rzeki','apartments':apartments}) output = template.render(variables) return HttpResponse(output)
{% if zmienna %} {% else %} {% endif %} {% for zmienna in kolekcja %} {% endfor %}Ich znaczenie jest chyba oczywiste. Zmienna w bloku {% if zmienna %} może byc dowolnego typu. Warunek if jest spełniony jeżeli zmienna istnieje i jest "niepusta" (np. jest True, jest różna od zera, jest niepustą kolekcją, ...).
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html; charset=utf-8" http-equiv="content-type"> <title>Rezerwacje</title> <link rel="stylesheet" href="media/style.css" type="text/css" /> </head> <body> <div style="text-align:center;"> <h2>Strona domowa pensjonatu "Pod kwiatami"</h2> <div><img src="media/bamberg.png" /></div> <p>{{podpis}}</p></div> <center> <h2>Lista apartamentów</h2> <table border="0px" width="70%"> {% for apartment in apartments %} <tr style="text-align:center;"> <td style="text-align:left;font-size:14pt;"> <p class="br">{{apartment.name}} <p class="br">Sypialnie: {{apartment.bedrooms}} <p class="br">Łóżka: {{apartment.beds}} <p class="br">{% if apartment.kitchenette %} Posiada aneks kuchenny {% else %} Nie posiada aneksu {% endif %} <p class="br"><a href="">Cennik</a> <p class="br"><a href="">Rezerwacja</a> </td> <td width="50%">{% if apartment.pathToPicture %} <img src="media/{{apartment.pathToPicture}}" width="600px" />{% endif %} </td> </tr> {% endfor %} </table> </center> <div style="text-align:center;"> <a href="Galery.html"><img class="middle" src="media/back.gif"/>Galeria</a> </div> </body> </html>