ORM Django
14 July 2008
Comments
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
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?
- Jeżeli klucz główny obiektu (primary key) ma wartość liczbową to Django wykonuje SELECT by sprawdzić czy rekord istnieje.
- Jeżeli rekord o podanym kluczu istnieje Django wykonuje UPDATE
- Jeżeli obiekt nie ma zdefiniowanego klucza lub rekord nie istnieje to django wykonuje INSERT
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()
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 2006Zagnież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))
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())
- Iterowanie: przy pierwszym przejściu zapytanie jest wykonywane
for e in Entry.objects.all(): print e.headline
- cięcie tablicy - użycie Pythonowej składni do cięcia tablic z parametrem step spowoduje wykonanie zapytania
- repl i len - notka - len nie powinno być stosowane do obliczania ilości wyników. Znacznie wydajniejszy jest SELECT COUNT
- list - wykonanie list() na QuerySet spowoduje wykonanie zapytania i wczytania wszystkiego do pamięci.
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')
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
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')
- gt - większe niż
- gte - większe lub równe niż
- lt - mniejsze niż
- lte - mniejsze lub równe
- in - wartość z możliwych z listy: Entry.objects.filter(id__in=[1, 3, 4])
- startswith - zaczyna się od
- istartswith - to samo, nie uwzględnia rozmiaru liter
- endswith i iendswith - kończy się na, drugi nie uwzględnia wielkości liter
- range - wartość z przedziału Entry.objects.filter(pub_date__range=(start_date, end_date))
- year - dla pól daty, określa rok jaki muszą spełniać
- month, day - odpowiednio miesiąc i dzień
RkBlog
Comment article