diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index 9754864eef5..4f3358eb8da 100644 --- a/django/db/models/query_utils.py +++ b/django/db/models/query_utils.py @@ -199,7 +199,7 @@ class DeferredAttribute: val = self._check_parent_chain(instance) if val is None: if instance.pk is None and self.field.generated: - raise FieldError( + raise AttributeError( "Cannot read a generated field from an unsaved model." ) instance.refresh_from_db(fields=[field_name]) diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index aa8b183f146..389e1e8370e 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -119,6 +119,7 @@ from .models import ( Simple, Sketch, Song, + Square, State, Story, StumpJoke, @@ -1175,6 +1176,10 @@ class TravelerAdmin(admin.ModelAdmin): autocomplete_fields = ["living_country"] +class SquareAdmin(admin.ModelAdmin): + readonly_fields = ("area",) + + site = admin.AdminSite(name="admin") site.site_url = "/my-site-url/" site.register(Article, ArticleAdmin) @@ -1298,6 +1303,7 @@ site.register(UserProxy) site.register(Box) site.register(Country, CountryAdmin) site.register(Traveler, TravelerAdmin) +site.register(Square, SquareAdmin) # Register core models we need in our tests site.register(User, UserAdmin) diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py index 85facf88214..de16796e85a 100644 --- a/tests/admin_views/models.py +++ b/tests/admin_views/models.py @@ -1134,3 +1134,14 @@ class Traveler(models.Model): related_name="favorite_country_to_vacation_set", 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"} diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index e7b2519eefd..164de1d01cb 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -6861,6 +6861,11 @@ class ReadonlyTest(AdminFieldExtractionMixin, TestCase): field = self.get_admin_readonly_field(response, "plotdetails") 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, '