Package: django-speedinfo
django-speedinfodjango-speedinfois a live profiling tool for Django projects to find
the most high loaded views for the next optimization.django-speedinfocounts
number of calls, cache hits, SQL queries, measures average and total call time
and more for each of your views. Detailed report and profiler controls are
available in Django admin.PrerequisitesPython 2.7, 3.6+Django 1.8+Installationpip install django-speedinfoUpgrading from 1.xOld profiling data will be unavailable after upgrading. Don't forget to export the data in advance.Setup one of the storage backends as shown in the section 4 ofSetupbelow.SPEEDINFO_PROFILING_CONDITIONSis empty by default. If you useSPEEDINFO_EXCLUDE_URLSin your
project you need to initialize the list of conditions explicitly:SPEEDINFO_PROFILING_CONDITIONS = ["speedinfo.conditions.exclude_urls.ExcludeURLCondition"]SPEEDINFO_REPORT_COLUMNSandSPEEDINFO_REPORT_COLUMNS_FORMATwere removed, useSPEEDINFO_ADMIN_COLUMNSinstead.
Every entry inSPEEDINFO_ADMIN_COLUMNSlist is a tuple (column name, value format, attribute name).
SeeCustomize admin columnsfor details. To add extra columns
follow the instruction in the sectionExtra admin columnsbelow.speedinfo.settingsmodule renamed tospeedinfo.confBase condition class was renamed fromConditiontoAbstractConditionSetupAddspeedinfotoINSTALLED_APPS.Addspeedinfo.middleware.ProfilerMiddlewareto the end ofMIDDLEWARE(orMIDDLEWARE_CLASSESfor Django < 1.10)
list, but beforedjango.middleware.cache.FetchFromCacheMiddleware(if used):MIDDLEWARE = [
    ...,
    "speedinfo.middleware.ProfilerMiddleware",
    "django.middleware.cache.FetchFromCacheMiddleware",
]Setup any cache backend (except local-memory and dummy caching) using our proxy cache backend.django-speedinfoneeds the cache to store profiler state between requests and to intercept calls to cache:CACHES = {
    "default": {
        "BACKEND": "speedinfo.backends.proxy_cache",
        "CACHE_BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
        "LOCATION": "/var/tmp/django_cache",
    }
}Setup storage for profiling data.django-speedinfocomes with two storages to choose from:Database storageAddspeedinfo.storage.databasetoINSTALLED_APPS.AddSPEEDINFO_STORAGE = "speedinfo.storage.database.storage.DatabaseStorage"to project settings.Runpython manage.py migrate.Cache storageAddSPEEDINFO_STORAGE = "speedinfo.storage.cache.storage.CacheStorage"to project settings.Optionally you may define a separate cache inCACHESto store profiling data.
To use it inCacheStorageassignSPEEDINFO_CACHE_STORAGE_CACHE_ALIASto the appropriate cache alias.
Example:CACHES = {
    "default": {
        "BACKEND": "speedinfo.backends.proxy_cache",
        "CACHE_BACKEND": "django.core.cache.backends.db.DatabaseCache",
        "LOCATION": "cache_table",
    },
    "speedinfo-storage": {
        "BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
        "LOCATION": "127.0.0.1:11211",
    },
})

SPEEDINFO_CACHE_STORAGE_CACHE_ALIAS = "speedinfo-storage"Runpython manage.py collectstatic.UsageOpenViews profilerin Django admin. Click theTurn on/Turn offbutton
to control profiler state. PressResetbutton to delete all profiling data.Advanced featuresCustom page cachingdjango-speedinfoautomatically detects when Django use per-site caching viaUpdateCacheMiddlewareandFetchFromCacheMiddlewaremiddlewares
or per-view caching viacache_pagedecorator and counts cache hit
when retrieving pages from the cache.If you implement your own caching logic and want to mark the view response
as obtained from the cache, add specified attribute to theHttpResponseobject
as shown below:from django.views import View
from from speedinfo.conf import speedinfo_settings

class CachedView(View):
    def get(self, request, *args, **kwargs):
        # ...
        # Assume that `response` was taken from the cache
        setattr(response, speedinfo_settings.SPEEDINFO_CACHED_RESPONSE_ATTR_NAME, True)
        return responseThe default value ofSPEEDINFO_CACHED_RESPONSE_ATTR_NAMEis_is_cached.
But you can override it if the attribute name is conflicts with your application logic.Customize admin columnsSPEEDINFO_ADMIN_COLUMNSallows to control visibility and appearance of Django admin
profiler columns. Every entry in theSPEEDINFO_ADMIN_COLUMNSlist is a tuple of
(column name, value format,ViewProfilerattribute name). Default value:SPEEDINFO_ADMIN_COLUMNS = (
    ("View name", "{}", "view_name"),
    ("HTTP method", "{}", "method"),
    ("Anonymous calls", "{:.1f}%", "anon_calls_ratio"),
    ("Cache hits", "{:.1f}%", "cache_hits_ratio"),
    ("SQL queries per call", "{}", "sql_count_per_call"),
    ("SQL time", "{:.1f}%", "sql_time_ratio"),
    ("Total calls", "{}", "total_calls"),
    ("Time per call", "{:.8f}", "time_per_call"),
    ("Total time", "{:.4f}", "total_time"),
)Extra admin columnsTo add additional data to a storage and columns to admin follow the instruction:Createcustom storage backendwhich will hold or calculate
additional fields.Implement storagefetch_all()method that will return the list of theViewProfilerinstances initialized with the extra fields. Example:def fetch_all(self, ordering=None):
    ...
    return [
        ViewProfiler(view_name="...", method="...", ..., extra_field="...")
        ...
    ]Implement sorting by extra fields infetch_all()method.Add extra fields toSPEEDINFO_ADMIN_COLUMNSas described in the sectionCustomize admin columns.Profiling conditionsSPEEDINFO_PROFILING_CONDITIONSallows to declare a list of condition classes
to filter profiling views by some rules. By defaultSPEEDINFO_PROFILING_CONDITIONSis empty.django-speedinfocomes with one build-in condition -ExcludeURLCondition. It allows to
exclude some urls from profiling by adding them to theSPEEDINFO_EXCLUDE_URLSlist.
Each entry inSPEEDINFO_EXCLUDE_URLSis a regex compatible expression to test requested url.
Usage example:SPEEDINFO_PROFILING_CONDITIONS = [
    "speedinfo.conditions.exclude_urls.ExcludeURLCondition",
]

SPEEDINFO_EXCLUDE_URLS = [
    r"/admin/",
    r"/news/$",
    r"/movie/\d+/$",
]To define your own condition class, you must inherit from the base classspeedinfo.conditions.base.AbstractConditionand implement all abstract methods. SeeExcludeURLConditionsource code for implementation example. Then add
full path to your class toSPEEDINFO_PROFILING_CONDITIONSlist as shown above. Conditions in mentioned list
are executed in a top-down order. The first condition returningFalseinterrupts the further check.Custom storage backenddjango-speedinfocomes withDatabaseStorageandCacheStorage. But you may want to write your
own storage (e.g. for MongoDB, Redis or even file-based). First create the storage class based onspeedinfo.storage.base.AbstractStorageand implement all abstract methods. Seespeedinfo.storage.cache.storageandspeedinfo.storage.database.storageas an examples. Then add path to your custom storage class
to the project settingsSPEEDINFO_STORAGE = "path.to.module.CustomStorage". Use our tests
to make sure that everything works as intended (you need to clone repository to get access to thetestspackage):from django.test import TestCase, override_settings
from tests.test_storage import StorageTestCase

@override_settings(
    SPEEDINFO_STORAGE="path.to.module.CustomStorage",
    SPEEDINFO_TESTS=True,
)
class CustomStorageTestCase(StorageTestCase, TestCase):
    passNoticeThe number of SQL queries measured bydjango-speedinfomay differ from the values
ofdjango-debug-toolbarfor the same view. It happens becausedjango-speedinfoshows the average number of SQL queries for each view. Also profiler doesn't take
into account SQL queries made in the preceding middlewares.