Предыдущий пост посвященный производительности, описывал Pony ORM, показавший фантастические результаты по сравнению с Django ORM и SQLAlchemy.
Впечатленный столь неординарными результатами и озабоченный производительностью собственного проекта, я решил внедрить Pony ORM в свой проект. Что из этого получилось, см подкатом.
Конечно, можно было бы переписать проект заново. Этот соблазн всегда витает над разработчиком, встретившим проблемы, корни которых лежат в используемом инструменте. Однако, объем уже написанного кода, огромная разветвленная модель данных, да и впечатляющее количество использованных в проекте вполне рабочих плагинов-приложений для Django ставят на этом пути большой и жирный крест.
Некоторое время назад, в поисках альтернативы Django ORM, я наткнулся на интересный прое��т Aldjemy. Это небольшая навеска над Django ORM, позволяющая использовать структуру моделей Django для построения альтернативной иерархии моделей SQLAlchemy. Такой подход дает возможность, сохраняя основу проекта (в том числе — всю модель данных Django), использовать SQLAlchemy именно и только там, где вы захотите. Вдохновленный идеей этого проектаи слизав некоторое количество строк кода, я сделал аналогичную библиотеку для прикрутки Pony ORM к Django ORM, назвав ее djony (DJango pONY).
Использование djony более чем просто. После установки djony в систему (например с помощью команды
Теперь у каждой из моделей Django (именно моделей — как классов) появился атрибут `p` (от слова pony). Это и есть модель Pony ORM. Ее можно использовать везде, где согласно документации Pony, нужно использовать модель. Вам понадобится также модуль orm, его можно импортировать из модуля pony (
Объекты моделей Pony ORM будут содержать только поля данных и коллекции объектов согласно модели данных и структуре отношений (возможно, в будущем надо будет прикрутить возможность добавления своих членов в автоматически создаваемые модели Pony ORM).
Попробуем теперь потестировать на производительность одну из самых популярных операций — проверку прав пользователя.
Для Django мы будем использовать готовую функцию User.has_perm. Разумеется, для Pony ORM нужно будет написать код, примерно эквивалентный этой функции::
Посмотрим на результаты тестирования (для тестирования, в базе было заведено 1000 пользователей, выполняющих для теста роль балласта).
Как видим, мы получили прирост более чем в 4 раза. Очень неплохо!
Впечатленный столь неординарными результатами и озабоченный производительностью собственного проекта, я решил внедрить Pony ORM в свой проект. Что из этого получилось, см подкатом.
Соблазны
Конечно, можно было бы переписать проект заново. Этот соблазн всегда витает над разработчиком, встретившим проблемы, корни которых лежат в используемом инструменте. Однако, объем уже написанного кода, огромная разветвленная модель данных, да и впечатляющее количество использованных в проекте вполне рабочих плагинов-приложений для Django ставят на этом пути большой и жирный крест.
Альтернатива
Некоторое время назад, в поисках альтернативы Django ORM, я наткнулся на интересный прое��т Aldjemy. Это небольшая навеска над Django ORM, позволяющая использовать структуру моделей Django для построения альтернативной иерархии моделей SQLAlchemy. Такой подход дает возможность, сохраняя основу проекта (в том числе — всю модель данных Django), использовать SQLAlchemy именно и только там, где вы захотите. Вдохновленный идеей этого проекта
Краткий экскурс
Использование djony более чем просто. После установки djony в систему (например с помощью команды
pip install git+git://github.com/nnseva/djony.git@master#egg=djony), мы можем указать djony в качестве одного из используемых приложений в settings.py. Нужно только помнить, что djony обязательно должен быть самым последним приложением в списке.Теперь у каждой из моделей Django (именно моделей — как классов) появился атрибут `p` (от слова pony). Это и есть модель Pony ORM. Ее можно использовать везде, где согласно документации Pony, нужно использовать модель. Вам понадобится также модуль orm, его можно импортировать из модуля pony (
from pony import orm). Альтернативно, вы можете использовать модуль djony.orm, содержащий все переменные модуля pony.orm, а также специфические для djony функции и переменные.Объекты моделей Pony ORM будут содержать только поля данных и коллекции объектов согласно модели данных и структуре отношений (возможно, в будущем надо будет прикрутить возможность добавления своих членов в автоматически создаваемые модели Pony ORM).
Тест
Попробуем теперь потестировать на производительность одну из самых популярных операций — проверку прав пользователя.
Для Django мы будем использовать готовую функцию User.has_perm. Разумеется, для Pony ORM нужно будет написать код, примерно эквивалентный этой функции::
def has_perm(user,perm):
if not user.is_active:
return False
app_label,codename = perm.split('.')
for p in orm.select(
p for p in Permission.p
if
(user in p.user_set or user in p.group_set.user_set) and
p.codename == codename and
p.content_type.app_label == app_label
):
return True
return False
Посмотрим на результаты тестирования (для тестирования, в базе было заведено 1000 пользователей, выполняющих для теста роль балласта).
>>> import test_pony
>>> import test_django
>>> test_django.test_django()
check user permissions: django req/seq: 170.308759221 req time (ms): 5.8716886
>>> test_pony.test_pony()
check user permissions: pony req/seq: 729.517146462 req time (ms): 1.3707697
Как видим, мы получили прирост более чем в 4 раза. Очень неплохо!
Приложение. Код тестов.
test_django.py
import datetime
from django.contrib.auth.models import User
def test_django():
t1 = datetime.datetime.now()
for i in range(10000):
test()
t2 = datetime.datetime.now()
print "check user permissions: django req/seq:",10000/(t2-t1).total_seconds(),'req time (ms):',(t2-t1).total_seconds()/10.
def test():
user = User.objects.get(username='testuser')
return user.has_perm('auth.add_user')
test_pony.py
import datetime
from django.contrib.auth.models import User, Permission
def test_pony():
t1 = datetime.datetime.now()
for i in range(10000):
test()
t2 = datetime.datetime.now()
print "check user permissions: pony req/seq:",10000/(t2-t1).total_seconds(),'req time (ms):',(t2-t1).total_seconds()/10.
from djony import orm
@orm.db_session
def test():
user = User.p.get(username='testuser')
return has_perm(user,'auth.add_user')
def has_perm(user,perm):
if not user.is_active:
return False
app_label,codename = perm.split('.')
for p in orm.select(
p for p in Permission.p
if
(user in p.user_set or user in p.group_set.user_set) and
p.codename == codename and
p.content_type.app_label == app_label
):
return True
return False
