Django ORM и QuerySets

В тази глава ще научите как Django се свързва с базата данни и съхранява данни в нея. Нека се потопим!

Какво е QuerySet?

QuerySet е по същество списък на обекти на даден Модел. QuerySets ви позволяват да четете данните от базата данни, да ги филтрирате и да ги подредите..

Най-лесно е да се учи чрез пример. Нека опитаме това, нали?

Django shell

Отворете вашата локална конзола (не на PythonAnywhere) и въведете тази команда:

command-line

(myvenv) ~/djangogirls$ python manage.py shell

Ефектът трябва да бъде такъв:

command-line

(InteractiveConsole)
>>>

Вече сте в интерактивната конзола на Django. Това е точно като Python конзолата, но с допълнителна магия на Django. :) Тук можете да използвате всички Python команди.

Всички обекти

Нека се опитаме първо да покажем всички наши публикации. Можете да направите това със следната команда:

command-line

>>> Post.objects.all()
Traceback (most recent call last):
      File "<console>", line 1, in <module>
NameError: name 'Post' is not defined

Ами сега! Появи се грешка. Това ни казва, че няма Post. Правилно е - забравихме да го внесем първо!

command-line

>>> from blog.models import Post

Импортираме модела Post от blog.models. Нека опитаме отново да покажем всички публикации:

command-line

>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>]>

Това е списък на публикациите, които създадохме по-рано! Създадохме тези публикации чрез администраторския интерфейс на Django. Но сега искаме да създаваме нови публикации с помощта на Python, така че как да направим това?

Създаване на обект

Ето как създавате нов обект Post в базата данни:

command-line

>>> Post.objects.create(author=me, title='Sample title', text='Test')

Но тук имаме една липсваща съставка: me. Трябва да предадем инстанция на модел User като автор. Как да направим това?

Нека първо да импортираме модел User:

command-line

>>> from django.contrib.auth.models import User

Какви потребители имаме в нашата база данни? Опитайте това:

command-line

>>> User.objects.all()
<QuerySet [<User: ola>]>

Това е суперпотребителят, който създадохме по-рано! Нека сега вземем потребителя (коригирайте този ред, за да използвате вашето потребителско име):

command-line

>>> me = User.objects.get(username='ola')

Както можете да видите, сега get a User с username, което се равнява на „ola“. Яко!

Сега най-накрая можем да създадем нашия пост:

command-line

>>> Post.objects.create(author=me, title='Sample title', text='Test')
<Post: Sample title>

Ура! Искате ли да проверите дали работи?

command-line

>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>, <Post: Sample title>]>

Ето, още една публикация в списъка!

Добавете още публикации

Вече можете да се позабавлявате малко и да добавяте още публикации, за да видите как работи. Добавете още две или три и след това преминете към следващата част.

Филтрирайте обекти

Голяма част от QuerySets е възможността да ги филтрирате. Да речем, че искаме да намерим всички публикации, на които потребителят ola е автор. Ще използваме filter вместо all в Post.objects.all(). В скобите посочваме на кое условие(я) трябва да отговаря блог публикацията, за да се озове в нашия набор от заявки. В нашия случай условието е author/0> да бъде равен на <code>me. Начинът да го напишем в Django е author=me. Сега нашата част от кода изглежда така:

command-line

>>> Post.objects.filter(author=me)
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>

Или може би искаме да видим всички публикации, които съдържат думата 'title' в полето title?

command-line

>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>, <Post: 4th title of post>]>

Забележка Има два знака за подчертаване (_) между title и contains. ORM на Django използва това правило за разделяне на имена на полета ("title") и операции или филтри ("contains"). Ако използвате само една долна черта, ще получите грешка като "FieldError: Не може да разреши ключовата дума title_contains".

Можете също така да получите списък с всички публикувани публикации. Правим това, като филтрираме всички публикации, които имат published_date са зададени в миналото:

command-line

>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet []>

За съжаление, публикацията, която добавихме от конзолата Python, все още не е публикувана. Но можем да променим това! Първо получете екземпляр от публикация, която искаме да публикуваме:

command-line

>>> post = Post.objects.get(title="Sample title")

И след това го публикувате с нашия метод publish:

command-line

>>> post.publish()

Сега опитайте отново да получите списък с публикувани публикации (натиснете клавиша със стрелка нагоре три пъти и натиснете enter):

command-line

>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: Sample title>]>

Подреждане на обекти

QuerySets също ви позволяват да поръчате списъка с обекти. Нека се опитаме да ги поръчаме от полето created_date:

command-line

>>> Post.objects.order_by('created_date')
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>

Можем също да обърнем подреждането, като добавим - в началото:

command-line

>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: 4th title of post>,  <Post: My 3rd post!>, <Post: Post number 2>, <Post: Sample title>]>

Сложни заявки чрез свързване на методи

Както видяхте, някои методи на Post.objects връщат QuerySet. Същите методи от своя страна могат също да бъдат извикани на QuerySet и след това ще върнат нов QuerySet. По този начин можете да комбинирате ефекта им, като ги свържете заедно:

>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
<QuerySet [<Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>, <Post: Sample title>]>

Това е наистина мощно и ви позволява да пишете доста сложни заявки.

Готино! Вече сте готови за следващата част! За да затворите конзолата, въведете това:

command-line

>>> exit()
$

results matching ""

    No results matching ""