Эффективная работа с моделями Django

Используем управляющие классы моделей и улучшаем производительность запросов

Перейдя от пятиминутных обучающих руководств к работе над реальными приложениями, программисты Django могут с легкостью создавать запутанные, сложно сопровождаемые или неэффективные классы моделей. Узнайте, как избежать типичных ошибок при создании запросов, использовать управляющие классы моделей для инкапсуляции сложных запросов и применять мощные возможности агрегации, появившиеся в Django 1.1.

Лиза Дэли, разработчик ПО и владелец компании, Threepress Consulting Inc.

Photo of Liza DalyЛиза Дэли – разработчик программного обеспечения, специализируется на приложениях для издательской индустрии. Она была ведущим разработчиком многих крупных онлайновых продуктов издательств Oxford University Press, O'Reilly Media и других. В настоящее время Лиза является независимым консультантом и основателем проекта Threepress, цель которого – разработка электронных книг.



04.03.2011

В Django большинство взаимодействий с базой данных осуществляется посредством механизма объектно-ориентированного отображения (Object-Relational Mapper или ORM) – функциональности, имеющейся, помимо Django, и в других современных инфраструктурах Web-разработки, таких как Rails. Системы ORM обретают все большую популярность среди разработчиков, так как они автоматизируют множество типичных взаимодействий с базой данных и используют знакомый объектно-ориентированный подход вместо инструкций SQL.

Django-программисты могут отказаться от использования «родной» системы ORM в пользу популярного пакета SQLAlchemy, однако хотя SQLAlchemy является довольно мощным инструментом, он сложнее в использовании, и при работе с ним приходится писать больше кода. Приложения Django можно разрабатывать, используя SQLAlchemy вместо встроенного механизма ORM (некоторые так и делают), но имейте в виду, что некоторые из наиболее привлекательных особенностей Django, такие как автоматическая генерация интерфейса администрирования, требуют использования встроенного ORM.

Часто используемые сокращения

  • API: интерфейс программирования приложений (Application programming interface)
  • HTML: язык разметки гипертекста (Hypertext Markup Language)
  • RDBMS: система управления реляционной базой данных (Relational database management system)
  • SQL: структурированный язык запросов (Structured Query Language)

Эта статья освещает некоторые малоизвестные возможности встроенного механизма ORM Django, но приводимые здесь сведения о типичных ошибках, приводящих к неэффективной генерации запросов, могут быть полезны и для пользователей SQLAlchemy.

В этой статье использовались следующие версии ПО:

  • Django 1.0.2 (в части 1 и 2)
  • Django 1.1 альфа версия (в части 3)
  • sqlite3
  • Python 2.4-2.6 (Django пока не поддерживает Python 3.)
  • IPython (для работы в консоли)

Механизм ORM Django поддерживает множество баз данных, среди которых проще всех в установке sqlite3. Кроме того, sqlite3 поставляется в комплекте со многими ОС. Примеры из этой статьи должны работать с любой базой данных. С полным списком баз данных, поддерживаемых Django, можно ознакомиться в разделе Ресурсы.

Учимся избегать типичных ошибок при генерации запросов с помощью ORM

Архитектура Django поощряет гибкий стиль разработки, предоставляющий возможности для быстрого создания прототипов и экспериментирования. На ранних стадиях разработки не стоит беспокоиться о производительности, лучше уделить больше внимания читаемости кода и простоте реализации.

Иногда обнаружить проблемы производительности удается довольно быстро. Часто они появляются при первой попытке запустить приложение с реальными данными. Это может стать очевидным, когда выполнение набора из нескольких тестов занимает больше 5 минут. В других случаях медленная работа приложения становится заметной визуально. К счастью, существуют некоторые шаблоны проблем производительности, которые легко идентифицировать и исправить. В листинге 1 (файл models.py приложения) и листинге 2 показан пример типичной ошибки.

Листинг 1. Базовые модели для приложения examples: файл models.py
from django.db import models

# Некоторый документ, такой как запись в блоге или wiki-страничка

class Document(models.Model):
    name = models.CharField(max_length=255)

# Генерируемый пользователем комментарий, похожий на комментарии на сайте
# Digg или Reddit

class Comment(models.Model):
    document = models.ForeignKey(Document, related_name='comments')
    content = models.TextField()

Об образцах кода

Django предоставляет удобный способ настройки рабочего окружения с помощью команды python manage.py shell. Во всех примерах кода, приводимых в этой статье, предполагается, что окружение настраивается именно таким образом.

В терминах Django, в этой статье предполагается следующее:

  • Проект Django называется better_models.
  • В проекте better_models имеется приложение с именем examples.

Приложение examples моделирует простую, похожую на блог систему документов, каждый из которых может иметь комментарии.

В листинге 2 показано, как можно осуществлять доступ к модели данных, показанной в листинге 1 неэффективным способом.

Листинг 2. Медленный доступ к моделям данных
from examples.model import *
import uuid

# Сначала создадим много документов и назначим им случайные имена

for i in range(0, 10000):
    Document.objects.create(name=str(uuid.uuid4()))

# Запрашиваем имена документов для последующего просмотра

names = Document.objects.values_list('name', flat=True)[0:5000]

# Медленный способ получения списка документов с 
# заданными именами

documents = []

for name in names:
    documents.append(Document.objects.get(name=name))

Это не совсем жизненный пример, который, однако, иллюстрирует довольно распространенный вариант использования моделей, когда для заданного списка идентификаторов требуется получить из базы данных все соответствующие им элементы.

Приведенный выше наивный код выполняется около 65 секунд при использовании размещаемой в оперативной памяти базе данных sqlite3. С базой данных, зависящей от файловой системы, он бы работал еще дольше. В листинге 3 показано, как исправить этот медленный код. Вместо выполнения запроса к базе данных для каждого имени, следует использовать оператор fieldname__in, который сгенерирует SQL-запрос, выглядящий примерно так:

SELECT * FROM model WHERE fieldname IN ('1', '2', ...)

(Точный синтаксис запроса будет различаться в зависимости от используемой базы данных.)

Листинг 3. Быстрый запрос для получения списка элементов
from examples import models
import uuid

for i in range(0, 10000):
    Document.objects.create(name=str(uuid.uuid4()))

names = Document.objects.values_list('name', flat=True)[0:5000]

documents = list(Document.objects.filter(name__in=names))

Этот код выполняется всего 3 секунды. Обратите внимание, что для того, чтобы запрос был действительно выполнен, в этом коде результат запроса преобразуется в список. Без этого сравнение было бы некорректным, так как в Django реализован отложенный механизм выполнения запросов, в котором простого присваивания результата запроса переменной недостаточно для фактического обращения к базе данных.

Гуру баз данных, для которых написание SQL-кода обычное дело, сочтут этот пример очевидным, но многие программисты Python не имеют существенного опыта работы с базами данных. Иногда самые хорошие привычки разработчика могут сыграть против эффективности. В листинге 4 показан один из способов рефакторинга кода из листинга 2, который можно было бы применить, не понимая его ошибочности.

Листинг 4. Типичный шаблон кода, приводящего к медленной работе с базой данных
for name in names:
    documents.append(get_document_by_name(name))

def get_document_by_name(name):
    return Document.objects.get(name=name))

С первого взгляда создание отдельного метода для извлечения документов из базы данных может показаться хорошей идеей. При необходимости в него можно поместить операции, которые следует выполнить перед извлечением документов, например добавление данных в модель. Запомните этот шаблон, разбиение кода на отдельные методы часто может казаться хорошим рефакторингом кода. Написание юнит-тестов с самого начала разработки и включение, по крайней мере, нескольких тестов, работающих с большими объемами данных, может помочь выявить ситуации, когда рефакторинг приводит к резкому падению производительности.


Инкапсуляция типичных запросов с помощью управляющих классов моделей

Встроенный управляющий класс модели, называемый Manager, используют все разработчики Django: именно он вызывается для всех методов формы Model.objects.*. Базовый класс Manager доступен автоматически и предоставляет часто используемые методы, возвращающие объекты QuerySet (например, all()), простые значения (например, count()) и объекты класса Model (например, get_or_create()).

Платформа Django поощряет разработчиков переопределять базовый класс Manager. Чтобы проиллюстрировать, почему это может быть полезным, добавим в приложение examples новую модель Format, которая описывает формат хранимых в системе файлов документов, например, как это показано в листинге 5.

Листинг 5. Добавление модели в приложение examples
from django.db import models

class Document(models.Model):
    name = models.CharField(max_length=255)
    format = models.ForeignKey('Format')

class Comment(models.Model):
    document = models.ForeignKey(Document, related_name='comments')
    content = models.TextField()

class Format(models.Model):
    type = models.CharField(choices=( ('Text file', 'text'),
                                      ('ePub ebook', 'epub'),
                                      ('HTML file', 'html')),
                            max_length=10)

Передовые техники обновления базы данных

Каждый раз при добавлении в models.py новой таблицы или новых столбцов в существующую таблицу необходимо повторно синхронизировать соответствующую базу данных. Воспользовавшись следующими советами, вы сможете делать это более эффективно.

  • На ранних стадиях разработки используйте только размещаемую в оперативной памяти базу данных, такую как sqlite3. Пользуйтесь возможностями по автоматической загрузке данных в базу из файлов с тестовым содержимым. Базы данных, размещаемые в оперативной памяти, работают достаточно быстро для одного пользователя и позволяют существенно сократить время ожидания при удалении и повторном создании таблиц в традиционных СУБД, таких как MySQL.
  • Придерживайтесь стиля разработки через тестирование. Инфраструктура тестирования Django каждый раз пересоздает базу данных с нуля, поэтому таблицы всегда будут актуальными. Применение этой функциональности в сочетании с размещаемой в оперативной памяти базой данных sqlite3 делает тестирование еще быстрее.
  • Попробуйте одну из многочисленных надстроек Django, управляющих синхронизацией базы данных. У меня был положительный опыт использования пакета django-evolution, кроме него имеются и другие пакеты. Больше информации о django-evolution можно найти в разделе Ресурсы.

Если вы решили использовать для разработки или тестирования sqlite3, обязательно проведите финальное интеграционное тестирование на рабочей базе данных. Для большинства случаев механизм ORM Django помогает сгладить различия между разными СУБД, но нет гарантии, что поведение будет во всем идентичным.

Далее воспользуемся измененной моделью и создадим несколько документов различных форматов(листинг 6).

Листинг 6. Создаем несколько документов различных форматов
# Сначала создадим набор объектов класса Format
# и сохраним их в базе данных

format_text = Format.objects.create(type='text')
format_epub = Format.objects.create(type='epub')
format_html = Format.objects.create(type='html')

# Создадим несколько документов в различных форматах
for i in range(0, 10):
    Document.objects.create(name='My text document',
                                   format=format_text)
    Document.objects.create(name='My epub document',
                                   format=format_epub)
    Document.objects.create(name='My HTML document', 
                                   format=format_html)

Допустим, нужно, чтобы приложение предоставляло возможность сначала фильтровать документы по формату, а затем фильтровать этот объект QuerySet по другим полям, например по названию. Следующий простой запрос возвращает только текстовые документы: Document.objects.filter(format=format_text).

В этом примере смысл запроса достаточно ясен, однако в крупных приложениях, возможно, на результат придется накладывать гораздо больше ограничений. Может быть, вы захотите выводить только документы, помеченные как публичные, или документы созданные не позднее, чем 30 дней назад. Если в приложении вам придется вызывать эти запросы в различных местах, то поддержка всех условий фильтрации в синхронизованном состоянии может стать источником ошибок и головной болью при сопровождении кода.

В таких ситуациях может помочь создание собственного управляющего класса модели. Собственные управляющие классы позволяют задавать неограниченное количество «шаблонных» запросов подобно методам встроенного управляющего класса модели, таким как latest() (который возвращает только последний экземпляр модели) или distinct() (который добавляет к сгенерированному запросу инструкцию SELECT DISTINCT). Управляющие классы не только сокращают дублирование кода в приложении, но также улучшают читаемость кода. Согласитесь, что спустя некоторое время по сравнению с кодом:

Documents.objects.filter(format=format_text,publish_on__week_day=todays_week_day, 
  is_public=True).distinct().order_by(date_added).reverse()

вам или новому разработчику будет гораздо проще понять следующий код:

Documents.home_page.all()

Создать собственный управляющий класс модели чрезвычайно просто. В листинге 7 показан пример создания для модели документа управляющего класса get_by_format.

Листинг 7. Собственный управляющий класс модели, предоставляющий методы для каждого типа формата документа
from django.db import models
                            
class DocumentManager(models.Manager):

    # Класс модели всегда доступен управляющему классу через
    # self.model, но в этом примере мы используем только метод
    # filter(), унаследованный от models.Manager.

    def text_format(self):
        return self.filter(format__type='text')

    def epub_format(self):
        return self.filter(format__type='epub')

    def html_format(self):
        return self.filter(format__type='html')

class Document(models.Model):
    name = models.CharField(max_length=255)
    format = models.ForeignKey('Format')

    # Новый управляющий класс модели
    get_by_format = DocumentManager()

    # Управляющий класс по умолчанию теперь нужно определять явно
    objects = models.Manager()


class Comment(models.Model):
    document = models.ForeignKey(Document, related_name='comments')
    content = models.TextField()

class Format(models.Model):
    type = models.CharField(choices=( ('Text file', 'text'),
                                      ('ePub ebook', 'epub'),
                                      ('HTML file', 'html')),
                            max_length=10)
    def __unicode__(self):
        return self.type

Несколько замечаний относительно этого кода.

  • Если вы создаете собственный управляющий класс модели, Django автоматически исключает управляющий класс по умолчанию. Я предпочитаю оставлять как управляющий класс модели по умолчанию, так и собственный управляющий класс, чтобы другие разработчики (или я сама, если забуду) могли все так же использовать objects, которые будут вести себя в точности так, как ожидается. Однако так как управляющий класс, доступный по имени get_by_format, является просто подклассом встроенного класса models.Manager, в нем доступны все методы по умолчанию, такие как all(). Делать или не делать одновременно доступными управляющий класс по умолчанию и собственный управляющий класс, зависит от личных предпочтений.
  • Также есть возможность напрямую назначать для objects новый управляющий класс. Единственный недостаток проявится, если вы захотите вручную переопределить изначальный класс QuerySet. В таком случае ваши новые objects могут вести себя неожиданным для других разработчиков образом.
  • Вам необходимо определить управляющий класс в models.py перед определением вашего класса модели, иначе он не будет доступным для Django. Это похоже на ограничения, имеющиеся у класса ForeignKey.
  • Можно было бы просто реализовать класс DocumentManager с единственным методом, принимающим аргумент, например with_format(format_name). Однако в общем случае я предпочитаю создавать методы управляющего класса с подробными именами, но не принимающие никаких аргументов.
  • Не существует технического ограничения на количество собственных управляющих классов, которые можно назначать модели, но маловероятно, что вам понадобится больше чем один или два.

Использовать методы нового управляющего класса модели достаточно просто.

In [1]: [d.format for d in Document.get_by_format.text_format()][0]
Out[1]: <Format: text>

In [2]: [d.format for d in Document.get_by_format.epub_format()][0]
Out[2]: <Format: epub>

In [3]: [d.format for d in Document.get_by_format.html_format()][0]
Out[3]: <Format: html>

Теперь появилось удобное место, в котором можно размещать любую функциональность, относящуюся к этим запросам, также сюда можно добавлять дополнительные ограничения, не засоряя код. Такой подход согласуется с видением в Django шаблона модель–вид–контроллер (model-view-controller или MVC), в соответствии с которым функциональность подобного рода следует размещать в models.py, а не скапливать ее в представлениях или шаблонах

Переопределяем изначальный класс QuerySet, возвращаемый пользовательским управляющим классом модели

В другом шаблоне реализации управляющих классов модели собственные методы вообще не создаются. Вместо определения нового метода, возвращающего только HTML-документы, можно определить управляющий класс, который будет работать только на этом ограниченном множестве данных. Пример показан в листинге 8.

Листинг 8. Пользовательский управляющий класс для HTML-документов
class HTMLManager(models.Manager):
    def get_query_set(self):
        return super(HTMLManager, self).get_query_set().filter(format__type='html')
    
class Document(models.Model):
    name = models.CharField(max_length=255)
    format = models.ForeignKey('Format')
html = HTMLManager()
    get_by_format = DocumentManager()
    objects = models.Manager()

В этом примере метод get_query_set() наследуется из models.Manager и переопределяется. В этом методе за основу берется базовый запрос (тот же самый, который генерируется методом all()), к которому затем применяется дополнительный фильтр. Все методы, которые мы будем впоследствии добавлять в этот управляющий класс, будут сначала вызывать метод get_query_set(), а затем применять к результату дополнительные методы запросов, как показано в листинге 9.

Листинг 9. Использование управляющего класса, работающего только с документами формата html
# Наш запрос HTML-документов возвращает то же количество
# документов, что и управляющий класс по умолчанию, явно выполняющий фильтрацию 
# данных.

In [1]: Document.html.all().count() 
Out[1]: 10

In [2]: Document.get_by_format.html_format().count()
Out[2]: 10

# Можно доказать, что они возвращают в точности один и тот же результат

In [3]: [d.id for d in Document.get_by_format.html_format()] == 
    [d.id for d in Document.html.all()]
Out[3]: True

# В HTMLManager() уже нельзя работать с нефильтрованными данными

In [4]: Document.html.filter(format__type='epub')
Out[4]: []

Используйте этот основанный на классе метод фильтрации запросов, когда вы ожидаете, что на некотором подмножестве ваших данных нужно будет выполнять много операций, и вы хотите уменьшить количество кода и сложность запросов, которые надо будет сгенерировать.

Использование классов и статических методов в моделях

Нет никаких ограничений на типы методов, которые можно добавлять в управляющий класс. Методы могут возвращать объекты QuerySet, как показано выше, или экземпляры соответствующего класса модели (доступного через self.model).

Возможно, в некоторых в случаях вам захочется выполнять операции, относящиеся к модели, но не возвращающие экземпляры класса модели или объекты QuerySets. Документация Django утверждает, что все методы, не работающие с экземплярами модели, следует помещать в управляющий класс модели. Однако есть и другая возможность: использовать для них классы Python и статические методы.

Вот простой пример вспомогательного метода, который относится ко всему классу Format, а не к какому-либо конкретному его экземпляру:

# Возвращает каноническое имя формата для некоторых часто 
# встречающихся в реальной жизни расширений

def check_extension(extension):
    if extension == 'text' or extension == 'txt' or extension == '.csv':
        return 'text'
    if extension.lower() == 'epub' or extension == 'zip':
        return 'epub'
    if 'htm' in extension:
        return 'html'
    raise Exception('Did not get known extension')

Этот код не принимает и не возвращает экземпляр класса Format, поэтому он не может быть методом экземпляра класса. Его можно было бы поместить в класс FormatManager, но так как этот метод вообще не обращается к базе данных, это место для него также не совсем подходит.

В качестве решения можно добавить этот метод в класс Format и объявить его статическим методом с помощью декоратора @staticmethod, как показано в листинге 10.

Листинг 10. Добавляем вспомогательную функцию в виде статического метода класса модели
class Format(models.Model):
    type = models.CharField(choices=( ('Text file', 'text'),
                                      ('ePub ebook', 'epub'),
                                      ('HTML file', 'html')),
                            max_length=10)
    @staticmethod
    def check_extension(extension):
        if extension == 'text' or extension == 'txt' or extension == '.csv':
            return 'text'
        if extension.lower() == 'epub' or extension == 'zip':
            return 'epub'
        if 'htm' in extension:
            return 'html'
        raise Exception('Did not get known extension')

    def __unicode__(self):
        return self.type

Этот метод можно вызывать в виде Format.check_extension(extension), и для этого не требуется иметь экземпляр класса Format или создавать управляющий класс.

В Python также имеется декоратор @classmethod, который генерирует методы, оперирующие над классами. Такие методы принимают в качестве первого аргумента сам класс. Это может быть полезно, когда вы хотите выполнить какую-либо интроспекцию класса, не создавая экземпляр этого класса.


Агрегирующие запросы в Django

В Django 1.1 в механизм ORM включены мощные методы запросов, позволяющие реализовывать функциональность, ранее доступную только через использование SQL напрямую. Для разработчиков Python, остерегающихся работать с SQL, и для всех, кто хочет поддерживать работоспособность своего Django-приложения с различными базами данных, это является действительно ценным нововведением.

В современных приложениях, ориентированных на общение пользователей, очень часто данные сортируются не по статическому полю, например по алфавиту или времени создания, а на основе динамических данных. Допустим, в приложении examples мы хотим сортировать документы по популярности, определяемой по количеству комментариев к документу. До Django 1.1 такое можно было сделать либо написав собственный SQL-код, либо реализовав непереносимую хранимую процедуру, либо, что хуже всего, написав несколько неэффективных объектно-ориентированных запросов. При другом подходе можно было бы определить в базе данных фиктивное поле для хранения желаемого значения (например, количества комментариев к документу) и обновлять это поле вручную, переопределив метод save() документа.

Механизм агрегации Django устраняет необходимость прибегать к таким хитростям. Теперь можно упорядочивать документы по количеству комментариев, используя лишь один метод QuerySet: annotate(). Пример приведен в листинге 11.

Листинг 11. Использование агрегации для упорядочения результатов по количеству комментариев
from django.db.models import Count

# Создадим несколько документов
unpopular = Document.objects.create(name='Unpopular document', format=format_html)
popular = Document.objects.create(name='Popular document', format=format_html)

# Документу "popular" добавим больше комментариев, чем документу "unpopular"
for i in range(0,10):
    Comment.objects.create(document=popular)

for i in range(0,5):
    Comment.objects.create(document=unpopular)

# Если мы возвращаем результаты, сортируя их по времени создания (по умолчанию по id),
# первым будет выведен документ "unpopular".
In [1]: Document.objects.all()
Out[1]: [<Document: Unpopular document>, <Document: Popular document>]

# Если же вместо этого мы аннотируем результат общим количеством комментариев
# у каждого документа и затем упорядочим его по этому вычисленному значению,
# то первым будет выведен документ "popular".

In [2]: Document.objects.annotate(Count('comments')).order_by('-comments__count')
Out[2]: [<Document: Popular document>, <Document: Unpopular document>]

Метод annotate() класса QuerySet сам по себе не выполняет никакой агрегации. Вместо этого он командует Django назначить значение переданного выражения псевдостолбцу в полученном результате. По умолчанию именем этого столбца является строка из названия предоставленного поля (здесь значение Comment.document.related_name()) и имени агрегирующего метода. В этом коде вызывается django.db.models.Count – одна из простых математических функций, доступных в библиотеке агрегации (с полным списком методов можно ознакомиться по ссылке в разделе Ресурсы).

Результатом вызова Document.objects.annotate(Count('comments')) является объект QuerySet, имеющий новое свойство comments__count. Чтобы переопределить имя по умолчанию, можно передать желаемое имя в качестве именованного аргумента.

Document.objects.annotate(popularity=Count('comments'))

Теперь, когда промежуточный объект QuerySet содержит количество комментариев, ассоциированных с каждым документом, можно упорядочить его по этому новому полю. Так как мы хотим вначале видеть документы с наибольшим количеством комментариев, задаем сортировку по убыванию: .order_by('-comments__count').

Использование агрегации не только сокращает количество кода, который приходится писать, но также гарантирует, что эти операции будут выполняться быстро, так как математические вычисления в них выполняются посредством базы данных. Такая реализация гораздо более эффективна, чем извлечение всех подходящих данных с помощью ORM с последующим выполнением вычислений вручную.

Другие типы агрегации в Django 1.1

Новая библиотека агрегации не просто позволяет возвращать более сложные результаты. Также можно возвращать в качестве результата данные, извлеченные напрямую из базы данных и не являющиеся объектами QuerySet. Например, чтобы получить среднее количество комментариев для всех документов в базе данных, используйте следующий код:

In [1]: from django.db.models import Avg
In [2]: Document.objects.aggregate(Avg('comments'))
Out[2]: {'comments__avg': 8.0}

Агрегацию можно применять как к отфильтрованным, так и неотфильтрованным запросам. Кроме того, можно фильтровать данные по столбцам, сгенерированным с помощью annotate, так же как по обычным столбцам. Также агрегирующие методы можно применять к объединениям данных. Например, можно агрегировать документы на основе рейтинга комментариев к ним, как это сделано в сайтах наподобие Slashdot. Больше информации об агрегации можно найти по ссылкам в разделе Ресурсы.


Заключение

Недостатком механизмов объектно-ориентированного отображения считается то, что они настолько сильно абстрагируют базу данных, что с их помощью невозможно писать эффективные масштабируемые приложения. Для определенного вида приложений, обслуживающих миллионы посетителей и имеющих тесно взаимосвязанные модели данных, это утверждение справедливо.

Однако подавляющее большинство Web-приложений никогда не добивается такой большой аудитории и не достигает такого уровня сложности. Механизмы ORM проектировались, чтобы ускорить разработку проектов и помочь программистам, не имеющим глубокого знания SQL, начать участвовать в проектах, основанных на базах данных. По мере того как ваше приложение становится все больше и популярнее, вам наверняка придется провести проверку его производительности, как описано в первом разделе этой статьи. Возможно, в итоге даже придется начать заменять ORM-код кодом SQL или хранимыми процедурами.

К счастью, возможности легкого в использовании механизма ORM Django продолжают развиваться. Библиотека агрегации, появившаяся в Django 1.1, является важным шагом вперед, позволяющим генерировать эффективные запросы, используя знакомый объектно-ориентированный синтаксис. Для достижения еще большей гибкости разработчики Python также могут попробовать работать с SQLAlchemy, особенно в написанных на Python Web-приложениях, которые не основаны на Django.

Ресурсы

Научиться

Получить продукты и технологии

  • Откройте для себя мощную альтернативу встроенному механизму ORM Django: SQLAlchemy. Этот инструмент может быть правильным выбором для очень больших приложений (EN).
  • SQLite V3: начиная с версии 2.5, в Python появилась поддержка SQLite 3 без необходимости в дополнительных драйверах. В ранних версиях Python для этого приходилось загружать пакет pysqlite (EN).
  • Разработайте ваш следующий проект с помощью пробного ПО от IBM, доступного для загрузки и на DVD (EN).
  • Загрузите ознакомительные версии продуктов IBM или поработайте с онлайновой пробной версией IBM SOA Sandbox и получите практический опыт с инструментами разработки и связующим ПО от DB2®, Lotus®, Rational®, Tivoli® и WebSphere® (EN).

Обсудить

  • Пишите в блогах и участвуйте в жизни сообщества developerWorks (EN).

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=630776
ArticleTitle=Эффективная работа с моделями Django
publish-date=03042011