Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
catcombo committed Dec 6, 2018
2 parents 0cd0bca + ad45e09 commit cc1e44e
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 102 deletions.
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
language: python
sudo: required
dist: xenial

python:
- "2.7"
- "3.6"
- "3.7"

services:
- mysql
Expand All @@ -16,11 +19,16 @@ env:
- DJANGO_VERSION=1.10
- DJANGO_VERSION=1.11
- DJANGO_VERSION=2.0
- DJANGO_VERSION=2.1

matrix:
exclude:
- python: "2.7"
env: DJANGO_VERSION=2.0
- python: "2.7"
env: DJANGO_VERSION=2.1
- python: "3.7"
env: DJANGO_VERSION=1.11

install:
- pip install -q Django==$DJANGO_VERSION
Expand Down
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

setup(
name='django-speedinfo',
version='1.3.6',
version='1.3.7',
packages=['speedinfo', 'speedinfo.migrations'],
include_package_data=True,
license='MIT',
Expand All @@ -28,13 +28,16 @@
'Framework :: Django :: 1.10',
'Framework :: Django :: 1.11',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
keywords='django profiler views performance',
install_requires=['Django>=1.8']
)
61 changes: 34 additions & 27 deletions speedinfo/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from django.conf.urls import url
from django.contrib import admin
from django.core.exceptions import PermissionDenied
from django.db.models import F, FloatField, ExpressionWrapper
from django.http import HttpResponseRedirect, HttpResponse

from speedinfo import profiler, settings
Expand All @@ -22,6 +21,23 @@
from django.core.urlresolvers import reverse


def field_wrapper(col):
"""Helper function to dynamically create list display method
for :class:`ViewProfilerAdmin` to control value formating
and sort order.
:type col: :data:`settings.ReportColumnFormat`
:rtype: function
"""
def field_format(obj):
return col.format.format(getattr(obj, col.attr_name))

field_format.short_description = col.name
field_format.admin_order_field = col.attr_name

return field_format


class ViewProfilerAdmin(admin.ModelAdmin):
list_display_links = None
actions = None
Expand All @@ -32,38 +48,29 @@ class Media:
'all': ('speedinfo/css/admin.css',)
}

def get_queryset(self, request):
qs = super(ViewProfilerAdmin, self).get_queryset(request)
return qs.annotate(
percall=ExpressionWrapper(F('total_time') / F('total_calls'), output_field=FloatField())
)

def get_list_display(self, request):
"""Creates and returns list of callables to represent
model field values with a custom format.
:param request: Request object
:type request: :class:`django.http.HttpRequest`
:return: list containing fields to be displayed on the changelist
def __init__(self, *args, **kwargs):
"""Initializes the list of visible columns and
the way they are formating the values.
"""
list_display = []
super(ViewProfilerAdmin, self).__init__(*args, **kwargs)
self.list_display = []

for rc in settings.SPEEDINFO_REPORT_COLUMNS_FORMAT:
if rc.attr_name in settings.SPEEDINFO_REPORT_COLUMNS:
method_name = '{}_wrapper'.format(rc.attr_name)
setattr(self, method_name, field_wrapper(rc))
self.list_display.append(method_name)

def wrapper(col):
def field_format(obj):
return col.format.format(getattr(obj, col.attr_name))
field_format.short_description = col.name
field_format.admin_order_field = col.order_field

return field_format
def get_queryset(self, request):
qs = super(ViewProfilerAdmin, self).get_queryset(request)

list_display.append(
wrapper(rc)
)
for rc in settings.SPEEDINFO_REPORT_COLUMNS_FORMAT:
if (rc.attr_name in settings.SPEEDINFO_REPORT_COLUMNS) and not isinstance(rc.order_field, str):
qs = qs.annotate(**{
rc.attr_name: rc.order_field
})

return list_display
return qs

def change_view(self, *args, **kwargs):
raise PermissionDenied
Expand Down Expand Up @@ -105,7 +112,7 @@ def export(self, request):
csv_writer = csv.writer(output)
csv_writer.writerow([col.name for col in export_columns])

for row in profiler.data.all():
for row in self.get_queryset(request):
csv_writer.writerow([
col.format.format(getattr(row, col.attr_name))
for col in export_columns
Expand Down
60 changes: 0 additions & 60 deletions speedinfo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,63 +19,3 @@ class ViewProfiler(models.Model):
class Meta:
verbose_name_plural = 'Views'
unique_together = ('view_name', 'method')

@property
def anon_calls_ratio(self):
"""Anonymous calls ratio.
:return: anonymous calls ratio percent
:rtype: float
"""
if self.total_calls > 0:
return 100 * self.anon_calls / float(self.total_calls)
else:
return 0

@property
def cache_hits_ratio(self):
"""Cache hits ratio.
:return: cache hits ratio percent
:rtype: float
"""
if self.total_calls > 0:
return 100 * self.cache_hits / float(self.total_calls)
else:
return 0

@property
def sql_time_ratio(self):
"""SQL time per call ratio.
:return: SQL time per call ratio percent
:rtype: float
"""
if self.total_time > 0:
return 100 * self.sql_total_time / float(self.total_time)
else:
return 0

@property
def sql_count_per_call(self):
"""SQL queries count per call.
:return: SQL queries count per call
:rtype: int
"""
if self.total_calls > 0:
return int(round(self.sql_total_count / float(self.total_calls)))
else:
return 0

@property
def time_per_call(self):
"""Time per call.
:return: time per call
:rtype: float
"""
if self.total_calls > 0:
return self.total_time / float(self.total_calls)
else:
return 0
9 changes: 0 additions & 9 deletions speedinfo/profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ def add(self, view_name, method, is_anon_call, is_cache_hit, sql_time, sql_count
total_time=F('total_time') + view_execution_time
)

def all(self):
"""Returns iterable object over all profiling data.
:return: profiling data
:rtype: :class:`typing.Iterable`
"""
from speedinfo.models import ViewProfiler
return ViewProfiler.objects.order_by('-total_time')

def reset(self):
"""Deletes all profiling data"""
from speedinfo.models import ViewProfiler
Expand Down
16 changes: 11 additions & 5 deletions speedinfo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from collections import namedtuple
from django.conf import settings
from django.db.models import ExpressionWrapper, F, FloatField, IntegerField

SPEEDINFO_CACHED_RESPONSE_ATTR_NAME = getattr(settings, 'SPEEDINFO_CACHED_RESPONSE_ATTR_NAME', 'is_cached')
SPEEDINFO_EXCLUDE_URLS = getattr(settings, 'SPEEDINFO_EXCLUDE_URLS', [])
Expand All @@ -13,11 +14,16 @@
SPEEDINFO_REPORT_COLUMNS_FORMAT = [
ReportColumnFormat('View name', '{}', 'view_name', 'view_name'),
ReportColumnFormat('HTTP method', '{}', 'method', 'method'),
ReportColumnFormat('Anonymous calls', '{:.1f}%', 'anon_calls_ratio', None),
ReportColumnFormat('Cache hits', '{:.1f}%', 'cache_hits_ratio', None),
ReportColumnFormat('SQL queries per call', '{}', 'sql_count_per_call', None),
ReportColumnFormat('SQL time', '{:.1f}%', 'sql_time_ratio', None),
ReportColumnFormat('Anonymous calls', '{:.1f}%', 'anon_calls_ratio',
ExpressionWrapper(100.0 * F('anon_calls') / F('total_calls'), output_field=FloatField())),
ReportColumnFormat('Cache hits', '{:.1f}%', 'cache_hits_ratio',
ExpressionWrapper(100.0 * F('cache_hits') / F('total_calls'), output_field=FloatField())),
ReportColumnFormat('SQL queries per call', '{}', 'sql_count_per_call',
ExpressionWrapper(F('sql_total_count') / F('total_calls'), output_field=IntegerField())),
ReportColumnFormat('SQL time', '{:.1f}%', 'sql_time_ratio',
ExpressionWrapper(100.0 * F('sql_total_time') / F('total_time'), output_field=FloatField())),
ReportColumnFormat('Total calls', '{}', 'total_calls', 'total_calls'),
ReportColumnFormat('Time per call', '{:.8f}', 'time_per_call', 'percall'),
ReportColumnFormat('Time per call', '{:.8f}', 'time_per_call',
ExpressionWrapper(F('total_time') / F('total_calls'), output_field=FloatField())),
ReportColumnFormat('Total time', '{:.4f}', 'total_time', 'total_time'),
]

0 comments on commit cc1e44e

Please sign in to comment.