Fixed #34842 -- Fixed ModelAdmin.readonly_fields crash with GeneratedFields.

This commit is contained in:
Paolo Melchiorre 2023-09-15 15:30:06 +02:00 committed by Mariusz Felisiak
parent aebedb7bd1
commit 2f1ab16be5
5 changed files with 24 additions and 3 deletions

View File

@ -199,7 +199,7 @@ class DeferredAttribute:
val = self._check_parent_chain(instance) val = self._check_parent_chain(instance)
if val is None: if val is None:
if instance.pk is None and self.field.generated: if instance.pk is None and self.field.generated:
raise FieldError( raise AttributeError(
"Cannot read a generated field from an unsaved model." "Cannot read a generated field from an unsaved model."
) )
instance.refresh_from_db(fields=[field_name]) instance.refresh_from_db(fields=[field_name])

View File

@ -119,6 +119,7 @@ from .models import (
Simple, Simple,
Sketch, Sketch,
Song, Song,
Square,
State, State,
Story, Story,
StumpJoke, StumpJoke,
@ -1175,6 +1176,10 @@ class TravelerAdmin(admin.ModelAdmin):
autocomplete_fields = ["living_country"] autocomplete_fields = ["living_country"]
class SquareAdmin(admin.ModelAdmin):
readonly_fields = ("area",)
site = admin.AdminSite(name="admin") site = admin.AdminSite(name="admin")
site.site_url = "/my-site-url/" site.site_url = "/my-site-url/"
site.register(Article, ArticleAdmin) site.register(Article, ArticleAdmin)
@ -1298,6 +1303,7 @@ site.register(UserProxy)
site.register(Box) site.register(Box)
site.register(Country, CountryAdmin) site.register(Country, CountryAdmin)
site.register(Traveler, TravelerAdmin) site.register(Traveler, TravelerAdmin)
site.register(Square, SquareAdmin)
# Register core models we need in our tests # Register core models we need in our tests
site.register(User, UserAdmin) site.register(User, UserAdmin)

View File

@ -1134,3 +1134,14 @@ class Traveler(models.Model):
related_name="favorite_country_to_vacation_set", related_name="favorite_country_to_vacation_set",
limit_choices_to={"continent": Country.ASIA}, limit_choices_to={"continent": Country.ASIA},
) )
class Square(models.Model):
side = models.IntegerField()
area = models.GeneratedField(
db_persist=True,
expression=models.F("side") * models.F("side"),
)
class Meta:
required_db_features = {"supports_stored_generated_columns"}

View File

@ -6861,6 +6861,11 @@ class ReadonlyTest(AdminFieldExtractionMixin, TestCase):
field = self.get_admin_readonly_field(response, "plotdetails") field = self.get_admin_readonly_field(response, "plotdetails")
self.assertEqual(field.contents(), "-") # default empty value self.assertEqual(field.contents(), "-") # default empty value
@skipUnlessDBFeature("supports_stored_generated_columns")
def test_readonly_unsaved_generated_field(self):
response = self.client.get(reverse("admin:admin_views_square_add"))
self.assertContains(response, '<div class="readonly">-</div>')
@ignore_warnings(category=RemovedInDjango60Warning) @ignore_warnings(category=RemovedInDjango60Warning)
def test_readonly_field_overrides(self): def test_readonly_field_overrides(self):
""" """

View File

@ -1,4 +1,3 @@
from django.core.exceptions import FieldError
from django.db import IntegrityError, connection from django.db import IntegrityError, connection
from django.db.models import F, FloatField, GeneratedField, IntegerField, Model from django.db.models import F, FloatField, GeneratedField, IntegerField, Model
from django.db.models.functions import Lower from django.db.models.functions import Lower
@ -93,7 +92,7 @@ class GeneratedFieldTestMixin:
def test_unsaved_error(self): def test_unsaved_error(self):
m = self.base_model(a=1, b=2) m = self.base_model(a=1, b=2)
msg = "Cannot read a generated field from an unsaved model." msg = "Cannot read a generated field from an unsaved model."
with self.assertRaisesMessage(FieldError, msg): with self.assertRaisesMessage(AttributeError, msg):
m.field m.field
def test_create(self): def test_create(self):