Выделите её мышкой и нажмите Enter
Знание о том, как можно создавать и изменять данные достаточно, но есть вероятность, что ваше приложение будет гораздо чаще обращаться к существующим объектам, чем создавать новые. Мы уже знаем способ получения каждой записи определённой модели:
>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>]
В общих чертах в SQL это выглядит так:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher;
Следует отметить, что Django не использует SELECT * при просмотре данных, а вместо этого явно перечисляет все поля. Так было задумано изначально: в некоторых случаях использование SELECT * может повлиять на производительность, а главное, перечисление полей более соответствует нормам Искусства программирования на языке Python: «Явное лучше неявного».
Для получения более подробной информации об Искусстве программирования на языке Python выполните в консоли Python команду import this.
Теперь внимательно рассмотрим строку Publisher.objects.all():
Сначала у нас есть определённая нами модель
Publisher
. Ничего удивительного:
при необходимости получить доступ к данным вы используете
модель.
Затем мы работаем с objects. Технически этот объект можно назвать менеджером. Менеджеры более подробно будут описаны в главе «Расширения для шаблонной системы». Сейчас вам надо знать только то, что менеджеры отвечают за операции «табличного уровня» над данными, что самое главное, включая операции выборки данных.
Все модели автоматически получают менеджер objects. Он используется при каждом доступе к данным.
Наконец, у нас есть all()
. Это метод
объекта objects, который возвращает все
записи, относящиеся к этой модели, из базы
данных. Несмотря на то, что этот объект
выглядит как список, в
действительности это набор данных (QuerySet) — объект, который представляет
собой набор записей из базы данных. Набор данных описан в
приложении «Справочник по API взаимодействия с базой данных». В
оставшейся части этой главы мы будем рассматривать этот
набор как список.
Любая выборка из базы данных работает по определённому шаблону — мы используем методы менеджера, который подключен к модели, по которой производится выборка.
Естественно, что достаточно редко требуется получать
весь набор данных из модели
единовременно. В большинстве случаев нам требуется обработать
небольшую часть данных. Мы можем осуществить это с помощью
метода filter()
:
>>> Publisher.objects.filter(name='Apress')
[<Publisher: Apress>]
Метод filter()
принимает именованные
аргументы, которые преобразуются в соответствующие SQL-условия
WHERE. Предыдущий пример будет преобразован в
нечто подобное:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';
Вы можете передать множество аргументов в
filter()
для сокращения диапазона
выборки:
>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>]
Множество аргументов будут объединены с помощью SQL операторов AND. Пример станет таким:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A.'
AND state_province = 'CA';
Следует отметить, что по умолчанию выборка использует SQL оператор = для точного совпадения. Также можно выполнять другие виды запросов:
>>> Publisher.objects.filter(name__contains="press")
[<Publisher: Apress>]
Обратите внимание на двойное подчёркивание между name и contains. Подобно Python это используется Django для выполнения «магических» действий. В данном случае __contains преобразовывается в SQL оператор LIKE:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name LIKE '%press%';
Доступны множество типов выборок, включая icontains (независящий от регистра LIKE), startswith и endswith, а также range (SQL оператор BETWEEN). В приложении «Справочник по API взаимодействия с базой данных» подробно описаны все типы выборок.
Вышеприведённые примеры использования
filter()
всегда возвращают
QuerySet
, который можно использовать
как список. Иногда более уместной является выборка
единственного объекта. Для этого предназначен метод
get()
:
>>> Publisher.objects.get(name="Apress")
<Publisher: Apress>
Вместо списка (т.е., набора данных
QuerySet
) возвращается только один
объект. По этой причине, запрос ожидающий множество объектов
вызовет исключение:
>>> Publisher.objects.get(country="U.S.A.")
Traceback (most recent call last):
...
MultipleObjectsReturned: get() returned more than one Publisher --
it returned 2! Lookup parameters were {'country': 'U.S.A.'}
Запрос не возвращающий ни одного объекта тоже вызовет исключение:
>>> Publisher.objects.get(name="Penguin")
Traceback (most recent call last):
...
DoesNotExist: Publisher matching query does not exist.
Исключение DoesNotExist
является атрибутом класса модели —
Publisher.DoesNotExist. В вашем приложении вы
можете перехватывать такие исключения:
try:
p = Publisher.objects.get(name='Apress')
except Publisher.DoesNotExist:
print "Apress isn't in the database yet."
else:
print "Apress is in the database."
В процессе изучения предыдущих примеров вы могли заметить, что объекты возвращаются в случайном порядке. Раз мы не указали в каком порядке нам возвращать результат выборки, база данных отдаёт его в удобном для себя виде.
Очевидно, что для вашего приложения потребуется отсортировать
результат по какому-нибудь значению, скажем, по алфавиту. Для
этого использую метод order_by()
:
>>> Publisher.objects.order_by("name")
[<Publisher: Apress>, <Publisher: O'Reilly>]
Это не сильно отличается от примера с методом
all()
, но SQL представление теперь
включает в себя оператор сортировки:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name;
Мы можем производить сортировку по любому полю:
>>> Publisher.objects.order_by("address")
[<Publisher: O'Reilly>, <Publisher: Apress>]
>>> Publisher.objects.order_by("state_province")
[<Publisher: Apress>, <Publisher: O'Reilly>]
Для выполнения сортировки по множеству полей (когда второе поле используется для сортировки элементов, у которых первое поле совпадает), используют множество аргументов:
>>> Publisher.objects.order_by("state_province", "address")
[<Publisher: Apress>, <Publisher: O'Reilly>]
Также мы можем указать необходимость выполнять обратную сортировку с помощью префикса -(минус) для имени поля:
>>> Publisher.objects.order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress>]
Несмотря на все возможности, постоянное использование
order_by()
может надоесть. Чаще всего
сортировку надо производить по жёстко определённому полю. В
этих случаях Django позволяет указать стандартную сортировку
для модели:
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __unicode__(self):
return self.name
class Meta:
ordering = ["name"]
Здесь мы ввели новую концепцию: класс
Meta
, который внедрён в определение
класса Publisher
(обратите внимание на
отступы). Вы можете использовать данный класс
Meta
с любой моделью для указания
различных параметров, влияющих на поведение модели. Полный
список данных параметров описан в приложении B FIXME, но
сейчас мы рассматривали только параметр
ordering. Если вы определите его, то пока не
будет использован явный вызов метода
order_by()
, все объекты
Publisher
будут выдаваться
отсортированными по полю name.
Вы знаете как фильтровать данные и как их сортировать. Вы желаете узнать как это делать одновременно? Для этого следует «сцепить» операторы вместе:
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress>]
Как вы можете предполагать, в SQL представлении это будет выглядеть так:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A'
ORDER BY name DESC;
Количество таких цепочек никак не ограничено[8].
Часто требуется получить только несколько строк результата выборки. Представьте, что в вашей базе находится несколько тысяч издателей, но вам надо отобразить только первого. Вы можете это осуществить с помощью возможностей стандартного списка Python:
>>> Publisher.objects.order_by('name')[0]
<Publisher: Apress>
Это преобразуется в:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 1;
Аналогично, вы можете получать определённый набор данных с помощью стандартного синтаксиса языка Python для работы со списками:
>>> Publisher.objects.order_by('name')[0:2]
Этот код вернёт два объекта и будет преобразован в:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
OFFSET 0 LIMIT 2;
Следует отметить, что отрицательные значения не поддерживаются:
>>> Publisher.objects.order_by('name')[-1]
Traceback (most recent call last):
...
AssertionError: Negative indexing is not supported.
Но получить результат всё же возможно. Просто воспользуйтесь
методом order_by()
:
>>> Publisher.objects.order_by('-name')[0]
Мы упоминали в разделе «Вставка и изменение данных» о том, что
метод save()
обновляет
все поля записи. Иногда полезно уметь
обновлять только выделенный набор полей.
Например, нам требуется изменить в объекте
Publisher
поле name с
«Apress» на «Apress Publishing». При
использовании save()
это выглядит так:
>>> p = Publisher.objects.get(name='Apress')
>>> p.name = 'Apress Publishing'
>>> p.save()
Это примерно преобразовывается в следующий SQL:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';
UPDATE books_publisher SET
name = 'Apress Publishing',
address = '2855 Telegraph Ave.',
city = 'Berkeley',
state_province = 'CA',
country = 'U.S.A.',
website = 'http://www.apress.com'
WHERE id = 52;
(Следует отметить, что данный пример предполагает, что нужный нам объект имеет идентификатор 52.)
Вы можете видеть в данном примере, что метод
save()
установит значения для
всех полей, не только для
name. Если в вашем случае, остальные поля могут
изменяться другими процессами, правильнее будет изменять
только поля, которые этого требуют. Для
этого следует использовать метод update()
объектов QuerySet
. Пример:
>>> Publisher.objects.filter(id=52).update(name='Apress Publishing')
SQL код будет более эффективным и не сможет вызвать «гонки»:
UPDATE books_publisher
SET name = 'Apress Publishing'
WHERE id = 52;
Метод update()
имеется у каждого
QuerySet
и это означает, что вы можете
изменять множество записей за раз. Вот так вы можете изменить
в поле country значение «U.S.A.»
на «USA» для каждой записи
Publisher
:
>>> Publisher.objects.all().filter(country='U.S.A.').update(country='USA')
2
Метод update()
вернул значение —
целое, представляющее количество изменённых записей.
>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>]
правильный вывод (согласно туториала):
[<Publisher: Addison-Wesley>, <Publisher: O'Reilly>, <Publisher: Apress Publishing>]
есть разница между Publisher.objects.all().filter и Publisher.objects.filter ?
как отфильтровать
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress' OR city = 'Berkeley'
Ответ на lewapa
как отфильтровать
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress' OR city = 'Berkeley'
Обратитесь к документации:
/rel1.4/topics/db/queries.html
Раздел: Сложные запросы с помощью объектов Q
У меня возвращает не просто целое, а целое и букву L(джанго 1.3.1), примерно вот так:
[code]>>> Publisher.objects.all().filter(country="USA").update(country="U.S.A")
3L[/code]
А что в доке по Python пишут про такой формат чисел?
Пока обучаюсь по линии сюжета, копать потом будем.
Сейчас проверил:
>>> t = Publisher.objects.all().filter(country= "USA").update(country="U.S.A")
>>> t
3L
>>> s = t+1
>>> s
4L
>>> s = int(t)
>>> s
3
На некоторое время остался спокоен :D
Интуитивно предполагаю, что буква L является индентификатором, возможно, целого числа. Обязательно разберусь, как только закончу с книгой. Django пополам с питоном доставляет. Поэтому интересно получить целостное понимание, и потом попробовать на пилотнике покопать вглубь. А вообще, Огромное Спасибо Вам!
Лучше возмитесь за туториал в доке, он короче и описывает текущую Django. Книга сильно устарела.