Embedding the high-performance Pony ORM in a Django project

    A previous performance post described Pony ORM with fantastic results compared to Django ORM and SQLAlchemy.

    Impressed by such extraordinary results and concerned about the performance of my own project, I decided to implement Pony ORM in my project. What came of it, see the roll.


    Temptations


    Of course, we could rewrite the project again. This temptation always hovers over the developer who has encountered problems whose roots lie in the tool used. However, the volume of already written code, a huge ramified data model, and the impressive amount of quite working plug-ins for Django used in the project put a big and bold cross on this path.

    Alternative


    Some time ago, in search of an alternative to Django ORM, I came across an interesting Aldjemy project . This is a small part of the Django ORM that allows you to use the Django model structure to build an alternative hierarchy of SQLAlchemy models. This approach makes it possible, while retaining the basis of the project (including the entire Django data model), to use SQLAlchemy exactly and only where you want. Inspired by the idea of ​​this project and licking a certain number of lines of code , I made a similar library for screwing Pony ORM to Django ORM, calling it djony (DJango pONY).

    Short excursion


    Using djony is more than easy. After installing djony on the system (for example, using the command pip install git+git://github.com/nnseva/djony.git@master#egg=djony), we can specify djony as one of the applications used in settings.py. Just remember that djony necessarily have to be the latest application in the list.

    Now, each of the Django models (namely models - as classes) has an attribute `p` (from the word pony). This is the Pony ORM model. It can be used wherever, according to the Pony documentation , you need to use a model. You will also need the orm module, it can be imported from the pony ( from pony import orm) module . Alternatively, you can use the djony.orm module, which contains all the variables of the pony.orm module, as well as djony-specific functions and variables.

    Pony ORM model objects will contain only data fields and object collections according to the data model and relationship structure (perhaps in the future it will be necessary to tighten the ability to add your members to automatically created Pony ORM models).

    Test


    Now let's try to test for performance one of the most popular operations - checking user rights.

    For Django, we will use the ready-made User.has_perm function. Of course, for Pony ORM you will need to write code roughly equivalent to this function:

    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
    


    Let's look at the test results (for testing, 1000 users were launched in the database, performing the role of ballast for the test).

    >>> 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
    


    As you can see, we have gained more than 4 times. Not bad!

    Application. Test code.



    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
    

    Also popular now: