Modele

Definiowanie struktur i relacji tabel w bazie danych

Model w Django służy do definiowania struktury i relacji tabel w bazie danych.
  • Każdy model jest klasą Pythona dziedziczącą django.db.models.Model
  • Każda właściwość klasy-modelu określa pole w bazie danych
  • Dane nie związane z polami w bazie danych umieszczane są w wewnętrznej klasie "Meta"
W django nie posługujemy się "na co dzień" językiem SQL. Operacje na bazach danych są przeprowadzane przez ORM Django.
Modele dla danej aplikacji znajdują się w pliku nazwa_aplikacji/models.py. Oto prosty przykład:
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
Definiujemy klasę Person posiadającą dwa pola - first_name i last_name. Czyli mamy klasę "zarządzającą" osobami zbierając ich imię i nazwisko. Dla powyższego modelu Django wygenerowałoby odpowiednią tabelę w bazie danych, a dokładniej (w przypadku postgresa):
CREATE TABLE mojaaplikacja_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);
Django automatycznie dodaje pole id (co można obejść) oraz automatycznie stosuje nazewnictwo tabel w postaci "mojaaplikacja_model" co też można obejść (czytaj dalej).
Po stworzeniu modelu by wygenerować tabele (i resztę danych typu uprawnienia) należy wykonać polecenie python manage.py syncdb w katalogu projektu.
Django nie posiada jeszcze opcji aktualizacji już istniejących tabel, co w przypadku zmian w modelach może nam przysporzyć trochę ręcznej pracy.

Pola w modelach

W powyższym przykładzie modelu pojawiło się pole CharFiled: models.CharField. Django ma zdefiniowaną listę różnych pól zdolnych przechowywać określone typy danych. Te pola jak już wiemy określają strukturę tabeli w bazie danych, jak również określają pewne zachowania frameworka. Kolejny przykład:
class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()
Mamy dwa modele - Muzyk i Album. Każdy album ma swojego autora - muzyka, co jest określane przez ForeignKey(Musician) - pole ForeignKey oznacza numer id wpisu z innego modelu (w tym przypadku id jakiegoś muzyka - model Musician). A żeby wszystko wyjaśnić - przegląd pól:
  • AutoField - pole IntegerField z automatycznie przyrastającymi wartościami. Zazwyczaj nie trzeba tego używać jako że Django domyślnie dodaje pole id tego typu do tabel.
  • BooleanField - Pole zawierające wartość Prawda/Fałsz. W panelu admina widoczne jako checkbox.
  • CharField - pole tekstowe na nieduże ilości tekstu, wymagany parametr max_length określa maksymalną długość. Dla większych ilości tekstu należy stosować TextField. Panel admina przedstawia to jako input text - jednowierszowe pole.
  • CommaSeparatedIntegerField - liczby całkowite oddzielone przecinkami. Parametr max_length wymagany.
  • DateField - Pola daty. Panel admina przedstawia to pole jako input text z kalendarzem.
  • DateTimeField - Data i czas.
  • EmailField - pole CharField do przechowywania adresów email. Sprawdza poprawność dodawanych danych, nie przyjmuje parametru max_length.
  • FileField - pole ładowania pliku. Wymaga parametru " upload_to" określającego pełną ścieżkę systemową - katalog, w którym ma być umieszczony plik. Ścieżka może zawierać formatowanie strftime. Dodatkowo należy w konfiguracji projektu określić MEDIA_ROOT - ścieżkę do katalogu z plikami statycznymi (w tym tymi ładowanymi). By ładowanie działało użytkownik, pod którym działa serwer musi mieć prawo zapisu dla podanego katalogu. upload_to określa nam do jakiego podkatalogu przesłać ładowany plik (względem MEDIA_ROOT). W bazie danych zapisana zostanie relatywna ścieżka do pliku względem MEDIA_ROOT. By w szablonie uzyskać pełną ścieżkę zastosuj {{ object.get_NAZWAPOLA_url }}.
  • FilePathField - pole z wyborem ograniczonym do nazw plików z określonego katalogu. Posiada trzy dodatkowe argumenty: path (wymagany) - określa ścieżkę do katalogu, z którego pole ma czerpać listę plików, match - wyrażenie regularne używane do filtrowania dostępnych plików. recursive - określa czy zawartość podkatalogów również powinna być uwzględniania, domyślnie False.
    FilePathField(path="/home/images", match="foo.*", recursive=True)
  • DecimalField, FloatField - pola dla liczb zmiennoprzecinkowych odpowiednio dla Pythonowych obiektów Decimal i Float. Wymaga dwóch dodatkowych argumentów: max_digits - maksymalna ilość cyfr, decimal_places - ilość cyfr po przecinku. Przykład, by zapisywać liczby do 999 z dwoma cyframi po przecinku zastosujemy:
    models.DecimalField(..., max_digits=5, decimal_places=2)
  • ImageField - pole takie jak FileField z tym że sprawdza czy plik jest grafiką. Posiada dwa opcjonalne argument - height_field i width_field, które jeżeli użyte będą przechowywały bierzące rozmiary grafiki. Wymaga Python Imaging Library.
  • IntegerField - Pole na liczby całkowite.
  • IPAddressField - Pole na adres IP.
  • NullBooleanField - Podobne do BooleanField lecz zezwala również na wartość "NULL". W Panelu Admina widoczne jako lista z opcjami "Tak", "Nie", "Nie wiadomo".
  • PhoneNumberField - Pole CharField sprawdzające poprawność podanej wartości jako numeru telefonu w USA - "XXX-XXX-XXXX".
  • PositiveIntegerField - Pole na dodatnie liczby całkowite.
  • PositiveSmallIntegerField - Jak powyższe z tym że ogranicza wartości zgodnie z ograniczeniami danej bazy danych.
  • SlugField - Pole stosowane jako etykieta czegoś (stosowanie na stronach z nowościami itd.) Zawierać może tylko liczby, litery i podkreślenia. Posiada opcjonalny parametr max_length określający długość (domyślnie 50). Zazwyczaj stosuje się to w linkach.
  • SmallIntegerField - Tak jak IntegerField lecz z ograniczeniem wartości takim jak dla danej bazy danych.
  • TextField - Pole na tekst. Reprezentowane w panelu admina przez textarea.
  • TimeField - Pole przechowujące czas.
  • URLField - Pole na adres URL. Django automatycznie sprawdza czy URL jest poprawny (tj. strona istnieje i nie zwraca błędu 404). By to wyłączyć należy podać parametr verify_exists=False.
  • USStateField - Dwuliterowy skrót stanu USA.
  • XMLField - Pole na dane w formacie XML. Wymaga parametru schema_path zawierającego ścieżkę do schematu RelaxNG, względem którego będzie sprawdzana poprawność.

Dodatkowe argumenty pól

Wszystkie pola przyjmują zestaw dodatkowych opcjonalnych argumentów:
  • null - Jeżeli ma wartość True django zapisze puste wartości jako NULL. Domyślnie fałsz.
  • blank - Jeżeli ma wartość True django dopuści puste pola. Odnosi się do walidacji formularzy.
  • choices - lista lub tupla dwóch tupli zawierająca możliwości do wyboru. W panelu admina input text zostanie zamieniony na select.
    YEAR_IN_SCHOOL_CHOICES = (
        ('FR', 'Freshman'),
        ('SO', 'Sophomore'),
        ('JR', 'Junior'),
        ('SR', 'Senior'),
        ('GR', 'Graduate'),
    )
    Pierwsza tupla zawiera wartości do zapisania, a druga czytelne dla ludzi opcje wyboru.
  • core - Dotyczy obiektów edytowanych przy zależnym innym obiekcie w Panelu Admina (inline edit). Pola z wartością core=True będę uważane za wymagane. Jeżeli wszystkie pola z tą opcją będą puste, obiekt zostanie skasowany.
  • db_column - opcjonalna nazwa (niestandardowa) tabeli.
  • db_index - Jeżeli True to django-admin.py sqlindexes wygeneruje polecenie CREATE INDEX dla danego pola.
  • default - Domyślna wartość pola.
  • help_text - Pomocniczy tekst wyświetlany w formularzach Panelu Admin
  • primary_key - Jeżeli True dane pole będzie miało atrybut PRIMARY KEY. Jeżeli nie podane to django automatycznie wygeneruje pole id z tym atrybutem.
  • unique - Jeżeli True pole będzie miało atrybut UNIQUE i będzie musiało zawierać unikalne (niepowtarzalne) wartości.

Relacje

MANY-TO-ONE - Wiele do jednego

Z tej zależności już skorzystaliśmy w przykładzie:
class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()
Gdzie wpis w jednej tabeli zależy (ma przypisany) od wpisu z innej tabeli. Zależność MANY-TO-ONE określana jest przez pole ForeignKey(MODEL). Zamiast nazwy modelu możemy podać "self" by uzyskać zależność modelu od siebie samego.

One-To-One - Jeden do jednego

Prosta relacja podobna do MANY-TO-ONE, z tym że jednemu rekordowi z tabeli A odpowiada jeden rekord z tabeli B. Obrazuje to poniższy przykład gdzie użytkownik może mieć tylko jeden profil.
class UserProfile(models.Model):
	user = models.OneToOneField(User, primary_key=True)
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=30)

MANY-TO-MANY - Wiele do wielu

Ta zależność nieco różni się od poprzedniej. Korzystając z wcześniejszego przykładu Album mógłby mieć wielu autorów/muzyków (a muzycy mogą mieć wiele albumów).
class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ManyToManyField(Musician)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()
Również w tej zależności można ustawić zależny model na "self" czyli zależność od siebie samego.

Metadane

Metadane służą do opisu i konfiguracji modelu. Umieszczamy je w klasie Meta:
class Foo(models.Model):
    bar = models.CharField(max_length=30)

    class Meta:
        # ...
W klasie Meta możemy określić kilka parametrów:
  • db_table - niestandardowa nazwa tabeli.
  • get_latest_by - określa nazwę pola typu DateField lub DateTimeField według wartości której sortować i określać "ostatnie wpisy" dla metody latest()
  • order_with_respect_to - sortowanie względem zależnego pola:
    class Answer(models.Model):
        question = models.ForeignKey(Question)
        # ...
    
        class Meta:
            order_with_respect_to = 'question'
    
  • ordering - oznacza domyślne sortowanie (pole i sposób).
    ordering = ['-order_date']
    ordering = ['-pub_date', 'author']
    Pierwszy przykład posortuje malejąco (znak -) a drugi posortuje malejąco względem pola pub_date a następnie rosnąco względem pola author. Znak ? posortuje elementy losowo.
  • permissions - określa dodatkowe (oprócz add, delete, change) uprawnienia dla obiektów danego modelu:
    permissions = (("czy_moze_costam", "Czy może cośtam"),)
    Jest to tupla złożona z podwójnych tupli gdzie pierwszy element to nazwa uprawnienia dla systemu a druga to nazwa uprawnienia czytelna dla człowieka.
  • unique_together - określa pola, które zestawione razem muszą być unikalne. Dotyczy to bazy danych i panelu admina.
    unique_together = (("driver", "restaurant"),)
    Jest to lista złożona z list zawierających nazwy pól.
  • verbose_name - nazwa obiektu czytelna dla człowieka.
  • verbose_name_plural - nazwa obiektu czytelna dla człowieka w liczbie mnogiej. Jeżeli nie podana django użyje verbose_name + "s"

Własne polecenia SQL

Django umożliwia wykonywanie własnych poleceń SQL poprzez API zgodne z Pythonowym DB-API (dokumentacja DB-API):
def my_custom_sql(self):
    from django.db import connection
    cursor = connection.cursor()
    cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
    row = cursor.fetchone()
    return row
blog comments powered by Disqus

Kategorie

Strony