From 6c120508b6445cb0d6198b4eacccd411960686d2 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:55:42 +0100 Subject: [PATCH] Refs #34462 -- Removed ModelAdmin.log_deletion() and LogEntryManager.log_action() per deprecation timeline. --- django/contrib/admin/models.py | 49 ------------------- django/contrib/admin/options.py | 34 -------------- docs/releases/6.0.txt | 3 ++ tests/admin_utils/models.py | 24 ---------- tests/admin_utils/test_logentry.py | 59 +---------------------- tests/modeladmin/tests.py | 75 ------------------------------ 6 files changed, 4 insertions(+), 240 deletions(-) diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py index bb81be8297..5723ebff7f 100644 --- a/django/contrib/admin/models.py +++ b/django/contrib/admin/models.py @@ -1,5 +1,4 @@ import json -import warnings from django.conf import settings from django.contrib.admin.utils import quote @@ -7,7 +6,6 @@ from django.contrib.contenttypes.models import ContentType from django.db import models from django.urls import NoReverseMatch, reverse from django.utils import timezone -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.text import get_text_list from django.utils.translation import gettext from django.utils.translation import gettext_lazy as _ @@ -26,56 +24,9 @@ ACTION_FLAG_CHOICES = [ class LogEntryManager(models.Manager): use_in_migrations = True - def log_action( - self, - user_id, - content_type_id, - object_id, - object_repr, - action_flag, - change_message="", - ): - warnings.warn( - "LogEntryManager.log_action() is deprecated. Use log_actions() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if isinstance(change_message, list): - change_message = json.dumps(change_message) - return self.model.objects.create( - user_id=user_id, - content_type_id=content_type_id, - object_id=str(object_id), - object_repr=object_repr[:200], - action_flag=action_flag, - change_message=change_message, - ) - def log_actions( self, user_id, queryset, action_flag, change_message="", *, single_object=False ): - # RemovedInDjango60Warning. - if type(self).log_action != LogEntryManager.log_action: - warnings.warn( - "The usage of log_action() is deprecated. Implement log_actions() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return [ - self.log_action( - user_id=user_id, - content_type_id=ContentType.objects.get_for_model( - obj, for_concrete_model=False - ).id, - object_id=obj.pk, - object_repr=str(obj), - action_flag=action_flag, - change_message=change_message, - ) - for obj in queryset - ] - if isinstance(change_message, list): change_message = json.dumps(change_message) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 25987171bf..3c2cf9d130 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -2,7 +2,6 @@ import copy import enum import json import re -import warnings from functools import partial, update_wrapper from urllib.parse import parse_qsl from urllib.parse import quote as urlquote @@ -56,7 +55,6 @@ from django.http.response import HttpResponseBase from django.template.response import SimpleTemplateResponse, TemplateResponse from django.urls import reverse from django.utils.decorators import method_decorator -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.html import format_html from django.utils.http import urlencode from django.utils.safestring import mark_safe @@ -967,28 +965,6 @@ class ModelAdmin(BaseModelAdmin): single_object=True, ) - def log_deletion(self, request, obj, object_repr): - """ - Log that an object will be deleted. Note that this method must be - called before the deletion. - - The default implementation creates an admin LogEntry object. - """ - warnings.warn( - "ModelAdmin.log_deletion() is deprecated. Use log_deletions() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - from django.contrib.admin.models import DELETION, LogEntry - - return LogEntry.objects.log_action( - user_id=request.user.pk, - content_type_id=get_content_type_for_model(obj).pk, - object_id=obj.pk, - object_repr=object_repr, - action_flag=DELETION, - ) - def log_deletions(self, request, queryset): """ Log that objects will be deleted. Note that this method must be called @@ -998,16 +974,6 @@ class ModelAdmin(BaseModelAdmin): """ from django.contrib.admin.models import DELETION, LogEntry - # RemovedInDjango60Warning. - if type(self).log_deletion != ModelAdmin.log_deletion: - warnings.warn( - "The usage of log_deletion() is deprecated. Implement log_deletions() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return [self.log_deletion(request, obj, str(obj)) for obj in queryset] - return LogEntry.objects.log_actions( user_id=request.user.pk, queryset=queryset, diff --git a/docs/releases/6.0.txt b/docs/releases/6.0.txt index 1f6f9a79da..e3f6c8afed 100644 --- a/docs/releases/6.0.txt +++ b/docs/releases/6.0.txt @@ -299,3 +299,6 @@ to remove usage of these features. * ``django.urls.register_converter()`` no longer allows overriding existing converters. + +* The ``ModelAdmin.log_deletion()`` and ``LogEntryManager.log_action()`` + methods are removed. diff --git a/tests/admin_utils/models.py b/tests/admin_utils/models.py index 8e812e27eb..243f314b03 100644 --- a/tests/admin_utils/models.py +++ b/tests/admin_utils/models.py @@ -1,5 +1,4 @@ from django.contrib import admin -from django.contrib.admin.models import LogEntry, LogEntryManager from django.db import models from django.utils.translation import gettext_lazy as _ @@ -87,26 +86,3 @@ class VehicleMixin(Vehicle): class Car(VehicleMixin): pass - - -class InheritedLogEntryManager(LogEntryManager): - model = LogEntry - - def log_action( - self, - user_id, - content_type_id, - object_id, - object_repr, - action_flag, - change_message="", - ): - return LogEntry.objects.create( - user_id=user_id, - content_type_id=content_type_id, - object_id=str(object_id), - # Changing actual repr to test repr - object_repr="Test Repr", - action_flag=action_flag, - change_message=change_message, - ) diff --git a/tests/admin_utils/test_logentry.py b/tests/admin_utils/test_logentry.py index e97441eb2e..491a220199 100644 --- a/tests/admin_utils/test_logentry.py +++ b/tests/admin_utils/test_logentry.py @@ -8,10 +8,9 @@ from django.contrib.contenttypes.models import ContentType from django.test import TestCase, override_settings from django.urls import reverse from django.utils import translation -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.html import escape -from .models import Article, ArticleProxy, Car, InheritedLogEntryManager, Site +from .models import Article, ArticleProxy, Car, Site @override_settings(ROOT_URLCONF="admin_utils.urls") @@ -236,22 +235,6 @@ class LogEntryTests(TestCase): logentry = LogEntry.objects.first() self.assertEqual(repr(logentry), str(logentry.action_time)) - # RemovedInDjango60Warning. - def test_log_action(self): - msg = "LogEntryManager.log_action() is deprecated. Use log_actions() instead." - content_type_val = ContentType.objects.get_for_model(Article).pk - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - log_entry = LogEntry.objects.log_action( - self.user.pk, - content_type_val, - self.a1.pk, - repr(self.a1), - CHANGE, - change_message="Changed something else", - ) - self.assertEqual(log_entry, LogEntry.objects.latest("id")) - self.assertEqual(ctx.filename, __file__) - def test_log_actions(self): queryset = Article.objects.all().order_by("-id") msg = "Deleted Something" @@ -289,46 +272,6 @@ class LogEntryTests(TestCase): ] self.assertSequenceEqual(logs, expected_log_values) - # RemovedInDjango60Warning. - def test_log_action_fallback(self): - LogEntry.objects2 = InheritedLogEntryManager() - queryset = Article.objects.all().order_by("-id") - content_type = ContentType.objects.get_for_model(self.a1) - self.assertEqual(len(queryset), 3) - msg = ( - "The usage of log_action() is deprecated. Implement log_actions() instead." - ) - with ( - self.assertNumQueries(3), - self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx, - ): - LogEntry.objects2.log_actions(self.user.pk, queryset, DELETION) - self.assertEqual(ctx.filename, __file__) - log_values = ( - LogEntry.objects.filter(action_flag=DELETION) - .order_by("id") - .values_list( - "user", - "content_type", - "object_id", - "object_repr", - "action_flag", - "change_message", - ) - ) - expected_log_values = [ - ( - self.user.pk, - content_type.id, - str(obj.pk), - "Test Repr", - DELETION, - "", - ) - for obj in queryset - ] - self.assertSequenceEqual(log_values, expected_log_values) - def test_recentactions_without_content_type(self): """ If a LogEntry is missing content_type it will not display it in span diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py index 00db6c19bc..3d2e8d00fb 100644 --- a/tests/modeladmin/tests.py +++ b/tests/modeladmin/tests.py @@ -21,7 +21,6 @@ from django.db import models from django.forms.widgets import Select from django.test import RequestFactory, SimpleTestCase, TestCase from django.test.utils import isolate_apps -from django.utils.deprecation import RemovedInDjango60Warning from .models import Band, Concert, Song @@ -891,80 +890,6 @@ class ModelAdminTests(TestCase): ] self.assertSequenceEqual(logs, expected_log_values) - # RemovedInDjango60Warning. - def test_log_deletion(self): - ma = ModelAdmin(Band, self.site) - mock_request = MockRequest() - mock_request.user = User.objects.create(username="bill") - content_type = get_content_type_for_model(self.band) - msg = "ModelAdmin.log_deletion() is deprecated. Use log_deletions() instead." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - created = ma.log_deletion(mock_request, self.band, str(self.band)) - self.assertEqual(ctx.filename, __file__) - fetched = LogEntry.objects.filter(action_flag=DELETION).latest("id") - self.assertEqual(created, fetched) - self.assertEqual(fetched.action_flag, DELETION) - self.assertEqual(fetched.content_type, content_type) - self.assertEqual(fetched.object_id, str(self.band.pk)) - self.assertEqual(fetched.user, mock_request.user) - self.assertEqual(fetched.change_message, "") - self.assertEqual(fetched.object_repr, str(self.band)) - - # RemovedInDjango60Warning. - def test_log_deletion_fallback(self): - class InheritedModelAdmin(ModelAdmin): - def log_deletion(self, request, obj, object_repr): - return super().log_deletion(request, obj, object_repr) - - ima = InheritedModelAdmin(Band, self.site) - mock_request = MockRequest() - mock_request.user = User.objects.create(username="akash") - content_type = get_content_type_for_model(self.band) - Band.objects.create( - name="The Beatles", - bio="A legendary rock band from Liverpool.", - sign_date=date(1962, 1, 1), - ) - Band.objects.create( - name="Mohiner Ghoraguli", - bio="A progressive rock band from Calcutta.", - sign_date=date(1975, 1, 1), - ) - queryset = Band.objects.all().order_by("-id")[:3] - self.assertEqual(len(queryset), 3) - msg = ( - "The usage of log_deletion() is deprecated. Implement log_deletions() " - "instead." - ) - with self.assertNumQueries(3): - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - ima.log_deletions(mock_request, queryset) - self.assertEqual(ctx.filename, __file__) - logs = ( - LogEntry.objects.filter(action_flag=DELETION) - .order_by("id") - .values_list( - "user_id", - "content_type", - "object_id", - "object_repr", - "action_flag", - "change_message", - ) - ) - expected_log_values = [ - ( - mock_request.user.id, - content_type.id, - str(obj.pk), - str(obj), - DELETION, - "", - ) - for obj in queryset - ] - self.assertSequenceEqual(logs, expected_log_values) - def test_get_autocomplete_fields(self): class NameAdmin(ModelAdmin): search_fields = ["name"]