Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DRF API Logger

[![Version](https://img.shields.io/badge/version-1.2.1-blue.svg)](https://github.com/vishalanandl177/DRF-API-Logger)
[![Version](https://img.shields.io/badge/version-1.2.2-blue.svg)](https://github.com/vishalanandl177/DRF-API-Logger)
[![Python](https://img.shields.io/badge/python-3.6+-blue.svg)](https://www.python.org)
[![Django](https://img.shields.io/badge/django-3.2+-green.svg)](https://djangoproject.com)
[![DRF](https://img.shields.io/badge/djangorestframework-3.12+-orange.svg)](https://www.django-rest-framework.org)
Expand Down Expand Up @@ -67,6 +67,33 @@ If using database logging, run migrations:
python manage.py migrate
```

> **Upgrade warning for large MySQL/MariaDB tables:** Version 1.2.0+ adds
> profiling-related columns (`profiling_data` and `sql_query_count`) to the
> `drf_api_logs` table. On large MySQL/MariaDB tables, adding columns can take
> locks or require table rebuilds depending on the database version, storage
> engine, row format, and existing table definition. Plan this migration like a
> production schema change.
>
> Before upgrading, inspect the SQL Django will run:
>
> ```bash
> python manage.py sqlmigrate drf_api_logger 0003
> ```
>
> For large MySQL/MariaDB deployments, validate the generated SQL against your
> exact database/version, prefer database-native online DDL where supported, and
> consider manually adding the columns with a safe online schema migration tool
> or database-native online DDL. If the columns are added manually, fake-apply
> the Django migration afterward:
>
> ```bash
> python manage.py migrate drf_api_logger 0003 --fake
> ```
>
> Avoid copying a generic `ALTER TABLE` command without validating it for your
> database. MySQL and MariaDB online DDL behavior differs by version and table
> definition.

## ⚙️ Quick Start

### Database Logging
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
project = 'DRF API Logger'
copyright = '2020, Vishal Anand'
author = 'Vishal Anand'
release = '1.2.0'
release = '1.2.2'

extensions = [
'sphinx.ext.autodoc',
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
DRF API Logger
==============

.. image:: https://img.shields.io/badge/version-1.2.0-blue.svg
.. image:: https://img.shields.io/badge/version-1.2.2-blue.svg
:alt: Version
.. image:: https://static.pepy.tech/personalized-badge/drf-api-logger?period=total&units=none&left_color=black&right_color=orange&left_text=Downloads%20Total
:target: http://pepy.tech/project/drf-api-logger
Expand Down
1 change: 1 addition & 0 deletions drf_api_logger/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Migration(migrations.Migration):
'verbose_name': 'API Log',
'verbose_name_plural': 'API Logs',
'db_table': 'drf_api_logs',
'ordering': ('-added_on',),
},
),
]
4 changes: 2 additions & 2 deletions drf_api_logger/migrations/0003_apilogsmodel_profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='apilogsmodel',
name='profiling_data',
field=models.TextField(blank=True, default=None, null=True),
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name='apilogsmodel',
name='sql_query_count',
field=models.PositiveIntegerField(blank=True, default=None, null=True),
field=models.PositiveIntegerField(blank=True, null=True),
),
]
2 changes: 0 additions & 2 deletions drf_api_logger/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,10 @@ class APILogsModel(BaseModel):
profiling_data = models.TextField(
null=True,
blank=True,
default=None,
)
sql_query_count = models.PositiveIntegerField(
null=True,
blank=True,
default=None,
)

def __str__(self):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def get_long_desc():

setuptools.setup(
name="drf-api-logger",
version="1.2.1",
version="1.2.2",
author="Vishal Anand",
author_email="vishalanandl177@gmail.com",
description="An API Logger for your Django Rest Framework project.",
Expand Down
18 changes: 17 additions & 1 deletion tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.test import TestCase, RequestFactory
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User
from django.db.models.fields import NOT_PROVIDED
from django.utils import timezone
from django.test.utils import override_settings
from unittest.mock import Mock, patch
Expand Down Expand Up @@ -152,6 +153,21 @@ def test_model_max_lengths(self):

self.assertEqual(len(log.api), 1024)

def test_profiling_fields_are_nullable_without_model_defaults(self):
"""Profiling fields should allow NULL without adding Python defaults."""
if not database_log_enabled():
self.skipTest("Database logging is not enabled")

profiling_field = self.APILogsModel._meta.get_field('profiling_data')
sql_query_count_field = self.APILogsModel._meta.get_field('sql_query_count')

self.assertTrue(profiling_field.null)
self.assertTrue(profiling_field.blank)
self.assertIs(profiling_field.default, NOT_PROVIDED)
self.assertTrue(sql_query_count_field.null)
self.assertTrue(sql_query_count_field.blank)
self.assertIs(sql_query_count_field.default, NOT_PROVIDED)


@override_settings(DRF_API_LOGGER_DATABASE=True)
class TestAdmin(TestCase):
Expand Down Expand Up @@ -311,4 +327,4 @@ def test_admin_slow_api_filter(self):
admin = APILogsAdmin(self.APILogsModel, self.site)

# Check that SlowAPIsFilter is in list_filter
self.assertIn(SlowAPIsFilter, admin.list_filter)
self.assertIn(SlowAPIsFilter, admin.list_filter)
Loading