RkBlog

Hardware, programming and astronomy tutorials and reviews.

ORM Django

Operowanie na danych zgromadzonych w bazie danych za pomocą obiektowego ORMa bez wykorzystania języka SQL. Artykuł opisuje jak pobierać, dodawać i modyfikować dane

Django dostarcza ci bogate API do operowania na danych umieszczonych w bazie danych. Po stworzeniu modeli możesz przystąpić do tworzenia widoków operujących na danych - dodawanie, pobieranie, edycja i inne operacje. Niniejszy artykuł będzie bazował na takim oto modelu blogów:
class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.URLField()

    def __unicode__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateTimeField()
    authors = models.ManyToManyField(Author)

    def __unicode__(self):
        return self.headline
Ulokowanego w mysite/blog/models.py (założenia do przykładu).

Dodawanie Danych

By dodać wpis do bazy danych wystarczy podać dane i wywołać save():
from mysite.blog.models import Blog
b = Blog(name='Blog Andrzeja', tagline='Najnowsze wieści z pola')
b.save()

Jeżeli tabela ma pole AutoField (zwiększające swą wartość, AUTO INCREMENT/SERIAL) to można pobrać id wpisu ale dopiero po jego zapisaniu, gdyż numer ID jest "obliczany" przez bazę a nie przez Django.
b2 = Blog(name='BlogSer', tagline='Przemyślenia o serze')
b2.id     # zwraca None - brak id jeszcze
b2.save()
b2.id     # tutaj dostaniemy id.

Zapisywanie zmian wygląda podobnie. W powyższym przykładzie b2 odnosi się do zapisanego obiektu. By zmienić dane wystarczy:
b2.name = 'Serowo'
b2.save()

Jak django odróżnia dodanie od aktualizacji?

Pobieranie Danych

Pobieranie danych wygląda nieco inaczej. Stosuje się do niego menadżera metody. By pobrać wszystkie wiersze wystarczy:
all_entries = MODEL.objects.all()
all_entries = Blog.objects.all()
Gdzie "MODEL" to nazwa wybranego przez nas modelu. Otrzymamy listę zawierającą rekordy z bazy danych.
By pobrać określone rekordy możemy skorzystać z filter() lub exclude():
Entry.objects.filter(pub_date__year=2006)
Co pobierze rekordy, których pola pub_date zawierają rok 2006

Zagnieżdżanie filtrów

Filtry można zagnieżdżać w taki sposób:
Entry.objects.filter(
    headline__startswith='What').exclude(
        pub_date__gte=datetime.now()).filter(
            pub_date__gte=datetime(2005, 1, 1))
Otrzymamy rekordy w których "headline" zaczyna się od "What" opublikowane (pub_date) między styczniem 2005 a dniem dzisiejszym.

Otrzymany wynik (obiekt QuerySet) można dalej zmieniać a otrzymane na nowo wyniki są nowym obiektem QuerySet niezależnym od wyniku-rodzica:
q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.now())
q3 = q1.filter(pub_date__gte=datetime.now())
Obiekty QuerySets nie pobierają danych z bazy przy ich definiowaniu. Dopiero pewne operacje wykonują narzucone zapytanie. Owe czynniki to:

Dodatkowe parametry wpływające na wynik

Ograniczanie ilości pobieranych wierszy jest proste:
Entry.objects.all()[:5] # LIMIT 5
Entry.objects.all()[5:10] # OFFSET 5 LIMIT 5
Entry.objects.all()[:10:2] # wykona zapytanie, zwróci co 2 rekord z pierwszych 10
Entry.objects.order_by('headline')[0] # jeden wiersz

Sortowanie wyników określone może być w modelu lecz także w zapytaniu można narzucić określone sortowanie:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

Za pomocą .distinct() można pobrać niepowtarzalne wiersze (SELECT DISTINCT).

.value() natomiast zwraca ValuesQuerySet i pozwala określić z jakich pól pobierać dane. Oprócz tego ValuesQuerySet jest listą słowników
Blog.objects.values('id', 'name')
Zwróci wszystkie wpisy z bazy danych ale ograniczone do pól "id" i "name".

dates(field, kind, order='ASC')
Zwraca listę niepowtarzalnych dat z pól typu DateField lub DateTimeField. field to nazwa takiego pola, kind to jedno z trzech: year", "month" lub "day" - odpowiednio zwrócą one unikalne lata, unikalne miesiąc/rok i unikalne dzień/miesiąc/rok. order określa kolejność (ASC lub DESC)

select_related() zwraca QuerySet, który dodatkowo podąża za wszystkimi ForeignKey:
e = Entry.objects.select_related().get(id=5)
b = e.blog
Co jest znacznie szybsze niż pobieranie danych "po kolei".

extra(select=None, where=None, params=None, tables=None)
Pozwala na dodanie własnego kodu SQL w pewnych miejscach zapytania. Należy stosować tylko w ostateczności.
count() zliczy ilość wierszy jaka byłaby zwrócona (SELECT COUNT)
delete() kasuje określone wpisy.

Przeszukiwanie pól

Możemy również tworzyć zapytania z LIKE i ILIKE, odpowiednio:
Entry.objects.get(headline__contains='Lennon')
Entry.objects.get(headline__icontains='Lennon')
Oprócz "contains" czy "icontains" mamy do dyspozycji:
RkBlog

14 July 2008;

Comment article