Package: django-performance-testing
Performance testing for Django through your automated tests!SetupUsageSupported LimitsQuerycountTimeSetting LimitsPredefined limit pointsSample SettingsAd-Hoc LimitsContext managers for python/django codeTemplate tag for templatessettings.DJPT_KNOWN_LIMITS_DOTTED_PATHSRelease NotesContributingReporting issues/improvementsPull RequestsSetting up all Python versionsCode of ConductDon’t wait with performance testing until the end of the project! We have learned
already that more frequent feedback on smaller chunks of changes is much better,
e.g.: TDD, CI, DevOps, Agile, etc.This library helps by providing performance testing from the start -
integrating it seamlessly into your existing development cycle, without
requiring changes to your development workflow.Unlike regular performance testing tools (ab,tsung, etc.), this
libary relies on indirect (proxy) indicators to performance - e.g.: the number
of queries executed. It’s a good rule of thumb that the more SQL there is, the
slower it will be. And this way “performance” testing won’t be slower than your
normal tests! (Disclaimer: while this tool is useful, classic performance
testing is still recommended!)Setupinstall it viapip installdjango-performance-testingadd it to your settings and it auto-registers itselfsettings.INSTALLED_APPS = [
   ...
   'django_performance_testing',
   ...
]Usageset your limits (see below for detail)and run your testmanage.py test <your app>For any limit violations, there will be a test failure.After the test run, you could generate theWorst Items Reportby runningmanage.py djpt_worst_report.The data is collected intosettings.DJPT_DATAFILE_PATHfile,
or intodjpt.results_collected.Supported LimitsQuerycountSets the limit in the number of queries executed inside the given scope.
Limits can be set for thetotalnumber of queries, or more specifically,
based on types of queries -read(SELECT),write(INSERT,UPDATE,DELETE), andother(e.g.:
transaction (savepoints)).When no (orNone) value is provided for a given limit type, that is
ignored during the check, as if there were no limit rules for. Thus it’s
possible to only focus on no write queries, while ignoring all the other queries
that might be executed.TimeSets the limit on thetotalelapsed seconds.Setting LimitsPredefined limit pointsFollowing are the keys that are currently supported forsettings.PERFORMANCE_LIMITSdictionarydjango.test.client.Client- every call to itsrequestmethod
is limited, i.e.:GET,POST, etc.Template.render- everyrendercall is checked for limits.
Note: it’s   recursive, i.e.:includeand similar tags result in a checkfor testcase classes, there istest method- the actual variousunittesttest methods that
you write for your apptest setUp- theTestCase.setUpmethods you write for your test
classestest tearDown- theTestCase.tearDownmethods you write for your
test classestest setUpClass- theTestCase.setUpClassmethods you write for
your test classestest tearDownClass- theTestCase.tearDownClassmethods you write for
your test classesFor each of the above keys, there is adictthat holds the actual limits.
The keys are the limit types (queriesand/ortime), and the value is
yet anotherdict, holding the actual limit values. For valid values, see
the description of the limits above, or look at the sample settingsSample SettingsPERFORMANCE_LIMITS = {
    'test method': {
        'queries': {'total': 50},  # want to keep the tests focused
        'time': {'total': 0.2},  # want fast integrated tests, so aiming for 1/5 seconds
    },
    'django.test.client.Client': {
        'queries': {
            'read': 30,
            'write': 8,  # do not create complex object structures in the web
                         # process
        },
    },
    'Template.render': {
        'queries': {
            'write': 0,  # rendering a template should never write to the database!
            'read': 0
        }
    }
}Ad-Hoc LimitsWhile the built-in measurement points are great, sometimes, when profiling
and trying to improve sections of the code, more granular limits are needed.Context managers for python/django codeAll limits can be used as context managers, e.g.:from django_performance_testing.queries import QueryBatchLimit
from django_performance_testing.timing import TimeLimit
...

def my_method_with_too_many_queries(request):
    with QueryBatchLimit(write=0, read=10):  # initialize form
        form = MyForm(request.POST)
    with QueryBatchLimit(write=0, read=3):  # validate it
        is_valid = form.is_valid()
    if is_valid:
        with QueryBatchLimit(read=0, write=8):  # save it
            form.save()
        with QueryBatchLimit(read=0, write=0):  # redirect
            return HttpResponseRedirect(...)
    else:
        with QueryBatchLimit(write=0):  # render form
            with TimeLimit(total=0.01):   # we need superfast templates
                return form_invalid(form)Template tag for templatesThere is a single template tag that can be used after{% load djpt_limits %},
namelydjptlimit. It takesa single string positional argument, the name of the limit - as persettings.DJPT_KNOWN_LIMITS_DOTTED_PATHS, see belowkeyword arguments that will be passed to the actual limit.It can be used directly in your tempaltes like{% load djpt_limits %}
{% djptlimit 'TimeLimit' total=3 %}
{{ slow_rendering }}
{% enddjptlimit %}When debugging more complext template hierarchies, where e.g.: the slow part
might not even be our own template, then{{ block.super }}could be helpful{% extends "base.html" %}
{% block title %}
{% djptlimit 'QueryBatchLimit' read=3 %}
{{ block.super }}
{% enddjptlimit %}
{% endblock %}settings.DJPT_KNOWN_LIMITS_DOTTED_PATHSThis is an array of full class paths, similar to howsettings.MIDDLEWAREare defined, e.g.:['django_performance_testing.timing.TimeLimit'].The name of the limit is the classname part of the class.Unless you have written a custom limit, this setting doesn’t need to be set explicitly,
as the app has defaults that include all limits.Release Notes0.7.3 - conform to latest flake80.7.1 - bugfix a test0.7.0 - separate data collection and reportingintroducedjpt_worst_reportmanagement commandbackwards incompatibe changes:Collectors are expected to haveget_sample_resultsmethod to allow easier and
more realistic testingWorst Items Report is not printed anymore after the test run.settings.DJPT_PRINT_WORST_REPORTdoesn’t have much effect anymore, will be
dropped in a subsequent release0.6.1add support for Django 1.11 (and thus for Python 3.6 too)0.6.0django test runner integration now usessettings.DJPT_KNOWN_LIMITS_DOTTED_PATHSfor the collectors/limits it initializes, thus allowing 3rd party collectors/limitsnew predefined limit points:test setUp,test tearDown,test setUpClass,test tearDownClass0.5.0backwards incompatible - remove--djpt-no-reportand usesettings.DJPT_PRINT_WORST_REPORTinstead to suppress the printing of the report
(to address incompatibilities with third party testrunner extensions)0.4.0add--djpt-no-reportargument to disable output of performance report on shell0.3.0introduceddjango_performance_testing.core.limits_registry. This keeps
track of all limits, and enforces that across the django project all limits
have unique names. This also warranted the introduction ofsettings.DJPT_KNOWN_LIMITS_DOTTED_PATHS.introduceddjptlimittemplate tag to be used for ad-hoc template
debugging0.2.0add timing measurement that can be limitedremove uniqueness check forcollector.id_, as the problems it caused
for testing outweighed its benefit for developer debugging aidbackwards incompatible:change how settings based limits are specifiedchange the worst report data output/data structure0.1.1 - bugfix releasebugfix: attributes set by on test methods (e.g.:@unittest.skip)
are now recognizable again and not lost due to the library’s patching0.1.0 - initial releasesupports Django 1.8, 1.9, 1.10 on python 2.7, 3.3, 3.4, and 3.5query counts are reported and can be limited, by categories -read,write,other, andtotalsupport ad-hoc limits by using it as a context managerpredefined limits support:django.test.client.Client- all calls to its request methodactualunittesttest_<foo>methodsTemplate.renderContributingAs an open source project, we welcome contributions.The code lives ongithub.Reporting issues/improvementsPlease open anissue on githubor provide apull requestwhether for code or for the documentation.For non-trivial changes, we kindly ask you to open an issue, as it might be rejected.
However, if the diff of a pull request better illustrates the point, feel free to make
it a pull request anyway.Pull Requestsfor code changesit must have tests covering the change. You might be asked to cover missing scenariosthe latestflake8will be run and shouldn’t produce any warningif the change is significant enough, documentation has to be providedSetting up all Python versionssudo apt-get -y install software-properties-common
sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
for version in 3.3 3.5 3.6; do
  py=python$version
  sudo apt-get -y install ${py} ${py}-dev
doneCode of ConductAs it is a Django extension, it followsDjango’s own Code of Conduct.
As there is no mailing list yet, please just email one of the main authors
(seesetup.pyfile orgithub contributors)