# Path: speedinfo/models.py
# class ViewProfiler(models.Model):
#     """
#     Model doesn't have associated table in the database.
#     So don't try to use it as an ordinary ORM model. You should
#     think of it as a dataclass. Model is used for wrapping
#     storage data and Django admin integration.
#     """
#     view_name = models.CharField("View name", max_length=255)
#     method = models.CharField("HTTP method", max_length=8)
#     anon_calls = models.PositiveIntegerField("Anonymous calls", default=0)
#     cache_hits = models.PositiveIntegerField("Cache hits", default=0)
#     sql_total_time = models.FloatField("SQL total time", default=0)
#     sql_total_count = models.PositiveIntegerField("SQL total queries count", default=0)
#     total_calls = models.PositiveIntegerField("Total calls", default=0)
#     total_time = models.FloatField("Total time", default=0)
# 
#     objects = ViewProfilerQuerySet.as_manager()
# 
#     class Meta:
#         verbose_name_plural = "Views"
#         managed = False
# 
#     def __init__(self, *args, **kwargs):
#         # Extract extra fields from parameters
#         extra_fields = {}
#         model_field_names = [field.attname for field in self._meta.get_fields()]
# 
#         for field_name in list(kwargs):
#             if field_name not in model_field_names:
#                 extra_fields[field_name] = kwargs.pop(field_name)
# 
#         super(ViewProfiler, self).__init__(*args, **kwargs)
# 
#         # Assign extra fields to the object if the field names
#         # do not override existing fields
#         for field_name, value in extra_fields.items():
#             if not getattr(self, field_name, None):
#                 setattr(self, field_name, value)
# 
#     @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


import mock
from django.contrib.auth.models import User
from django.test import TestCase, override_settings
from speedinfo.models import ViewProfiler
    from django.urls import reverse  # Django >= 1.10
    from django.core.urlresolvers import reverse
        ("HTTP method", "{}", "method"),
        ("Total calls", "{}", "total_calls"),
        ("Time per call", "{:.4f}", "time_per_call"),
        ("Total time", "{:.2f}", "total_time"),
    ))
    @mock.patch("speedinfo.managers.profiler")
    def test_partial_export(self, profiler_mock):
        profiler_mock.storage.fetch_all.return_value = [
            ViewProfiler(
                view_name="app.view_name", method="GET", anon_calls=8, cache_hits=3,
                sql_total_time=40, sql_total_count=20, total_calls=10, total_time=50,
            ),
        ]
        response = self.client.get(reverse("admin:speedinfo-profiler-export"))
        output = response.content.decode()

        self.assertEqual(
            output,
            "View name,HTTP method,Total calls,Time per call,Total time\r\n"
            "app.view_name,GET,10,5.0000,50.00\r\n",
        )

    @override_settings(SPEEDINFO_ADMIN_COLUMNS=(
        ("View name", "{}", "view_name"),
        ("HTTP method", "{}", "method"),
        ("Extra", "{}", "extra"),
    ))
    @mock.patch("speedinfo.admin.profiler")
    def test_extra_columns_admin_index(self, profiler_mock):
        profiler_mock.storage.fetch_all.return_value = [

# Path: speedinfo/models.py
# class ViewProfiler(models.Model):
#     """
#     Model doesn't have associated table in the database.
#     So don't try to use it as an ordinary ORM model. You should
#     think of it as a dataclass. Model is used for wrapping
#     storage data and Django admin integration.
#     """
#     view_name = models.CharField("View name", max_length=255)
#     method = models.CharField("HTTP method", max_length=8)
#     anon_calls = models.PositiveIntegerField("Anonymous calls", default=0)
#     cache_hits = models.PositiveIntegerField("Cache hits", default=0)
#     sql_total_time = models.FloatField("SQL total time", default=0)
#     sql_total_count = models.PositiveIntegerField("SQL total queries count", default=0)
#     total_calls = models.PositiveIntegerField("Total calls", default=0)
#     total_time = models.FloatField("Total time", default=0)
# 
#     objects = ViewProfilerQuerySet.as_manager()
# 
#     class Meta:
#         verbose_name_plural = "Views"
#         managed = False
# 
#     def __init__(self, *args, **kwargs):
#         # Extract extra fields from parameters
#         extra_fields = {}
#         model_field_names = [field.attname for field in self._meta.get_fields()]
# 
#         for field_name in list(kwargs):
#             if field_name not in model_field_names:
#                 extra_fields[field_name] = kwargs.pop(field_name)
# 
#         super(ViewProfiler, self).__init__(*args, **kwargs)
# 
#         # Assign extra fields to the object if the field names
#         # do not override existing fields
#         for field_name, value in extra_fields.items():
#             if not getattr(self, field_name, None):
#                 setattr(self, field_name, value)
# 
#     @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


# Path: tests/test_admin.py
import mock
from django.contrib.auth.models import User
from django.test import TestCase, override_settings
from speedinfo.models import ViewProfiler
    from django.urls import reverse  # Django >= 1.10
    from django.core.urlresolvers import reverse

        ("HTTP method", "{}", "method"),
        ("Total calls", "{}", "total_calls"),
        ("Time per call", "{:.4f}", "time_per_call"),
        ("Total time", "{:.2f}", "total_time"),
    ))
    @mock.patch("speedinfo.managers.profiler")
    def test_partial_export(self, profiler_mock):
        profiler_mock.storage.fetch_all.return_value = [
            ViewProfiler(
                view_name="app.view_name", method="GET", anon_calls=8, cache_hits=3,
                sql_total_time=40, sql_total_count=20, total_calls=10, total_time=50,
            ),
        ]
        response = self.client.get(reverse("admin:speedinfo-profiler-export"))
        output = response.content.decode()

        self.assertEqual(
            output,
            "View name,HTTP method,Total calls,Time per call,Total time\r\n"
            "app.view_name,GET,10,5.0000,50.00\r\n",
        )

    @override_settings(SPEEDINFO_ADMIN_COLUMNS=(
        ("View name", "{}", "view_name"),
        ("HTTP method", "{}", "method"),
        ("Extra", "{}", "extra"),
    ))
    @mock.patch("speedinfo.admin.profiler")
    def test_extra_columns_admin_index(self, profiler_mock):
        profiler_mock.storage.fetch_all.return_value = [

            ViewProfiler(view_name="app.view_name", method="GET", extra="Value"),