Kaydet (Commit) 8dc675d9 authored tarafından shanghui's avatar shanghui Kaydeden (comit) Tim Graham

Fixed #28838 -- Fixed Model.save() crash if the base manager annotates with a related field.

üst cbac11f9
......@@ -701,6 +701,8 @@ class QuerySet:
"Cannot update a query once a slice has been taken."
query = self.query.chain(sql.UpdateQuery)
query.add_update_fields(values)
# Clear any annotations so that they won't be present in subqueries.
query._annotations = None
self._result_cache = None
return query.get_compiler(self.db).execute_sql(CURSOR)
_update.alters_data = True
......
......@@ -25,6 +25,13 @@ class PublishedBookManager(models.Manager):
return super().get_queryset().filter(is_published=True)
class AnnotatedBookManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
favorite_avg=models.Avg('favorite_books__favorite_thing_id')
)
class CustomQuerySet(models.QuerySet):
def filter(self, *args, **kwargs):
queryset = super().filter(fun=True)
......@@ -131,7 +138,6 @@ class Book(models.Model):
title = models.CharField(max_length=50)
author = models.CharField(max_length=30)
is_published = models.BooleanField(default=False)
published_objects = PublishedBookManager()
authors = models.ManyToManyField(Person, related_name='books')
fun_authors = models.ManyToManyField(FunPerson, related_name='books')
favorite_things = GenericRelation(
......@@ -145,6 +151,12 @@ class Book(models.Model):
object_id_field='favorite_thing_id',
)
published_objects = PublishedBookManager()
annotated_objects = AnnotatedBookManager()
class Meta:
base_manager_name = 'annotated_objects'
def __str__(self):
return self.title
......
......@@ -617,6 +617,22 @@ class CustomManagersRegressTestCase(TestCase):
book.refresh_from_db()
self.assertEqual(book.title, 'Hi')
def test_save_clears_annotations_from_base_manager(self):
"""Model.save() clears annotations from the base manager."""
self.assertEqual(Book._meta.base_manager.name, 'annotated_objects')
book = Book.annotated_objects.create(title='Hunting')
Person.objects.create(
first_name='Bugs', last_name='Bunny', fun=True,
favorite_book=book, favorite_thing_id=1,
)
book = Book.annotated_objects.first()
self.assertEqual(book.favorite_avg, 1) # Annotation from the manager.
book.title = 'New Hunting'
# save() fails if annotations that involve related fields aren't
# cleared before the update query.
book.save()
self.assertEqual(Book.annotated_objects.first().title, 'New Hunting')
def test_delete_related_on_filtered_manager(self):
"""Deleting related objects should also not be distracted by a
restricted manager on the related object. This is a regression
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment