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
2 changes: 1 addition & 1 deletion django/db/models/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ async def acreate(self, **kwargs):
def _prepare_for_bulk_create(self, objs):
objs_with_pk, objs_without_pk = [], []
for obj in objs:
obj._prepare_related_fields_for_save(operation_name="bulk_create")
if isinstance(obj.pk, DatabaseDefault):
objs_without_pk.append(obj)
elif obj._is_pk_set():
Expand All @@ -757,7 +758,6 @@ def _prepare_for_bulk_create(self, objs):
objs_with_pk.append(obj)
else:
objs_without_pk.append(obj)
obj._prepare_related_fields_for_save(operation_name="bulk_create")
return objs_with_pk, objs_without_pk

def _check_bulk_create_options(
Expand Down
5 changes: 4 additions & 1 deletion docs/releases/6.0.8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ bugs in 6.0.7.
Bugfixes
========

* ...
* Fixed a regression in Django 6.0 that caused
:meth:`~django.db.models.query.QuerySet.bulk_create` to crash on databases
that support returning rows from bulk inserts when a related object providing
the primary key was saved after assignment (:ticket:`37234`).
21 changes: 21 additions & 0 deletions tests/basic/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,3 +1099,24 @@ def test_refresh_overwrites_queryset_fields(self):
with self.assertNumQueries(1):
a.refresh_from_db(fields=["headline"], from_queryset=from_queryset)
self.assertEqual(a.headline, headline)

def test_refresh_copies_fetch_mode_from_plucked_instance(self):
a = Article.objects.create(pub_date=datetime.now())
fa = FeaturedArticle.objects.fetch_mode(models.FETCH_PEERS).create(article=a)

from_queryset = FeaturedArticle.objects.fetch_mode(models.RAISE).select_related(
"article"
)
fa.refresh_from_db(from_queryset=from_queryset)
self.assertEqual(fa._state.fetch_mode, models.FETCH_PEERS)
self.assertEqual(fa.article._state.fetch_mode, models.RAISE)

def test_refresh_ignores_fetch_mode_if_no_instance_plucked(self):
a = Article.objects.create(pub_date=datetime.now())
fa = FeaturedArticle.objects.fetch_mode(models.FETCH_PEERS).create(article=a)

# This queryset's fetch mode is not used because no fields are plucked.
from_queryset = FeaturedArticle.objects.fetch_mode(models.RAISE)
fa.refresh_from_db(from_queryset=from_queryset)
self.assertEqual(fa._state.fetch_mode, models.FETCH_PEERS)
self.assertEqual(fa.article._state.fetch_mode, models.FETCH_PEERS)
7 changes: 7 additions & 0 deletions tests/bulk_create/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,13 @@ def test_nullable_fk_after_parent_bulk_create(self):
child = NullableFields.objects.get(integer_field=88)
self.assertEqual(child.auto_field, parent)

def test_pk_from_related_instance_saved_after_init(self):
country = Country(name="Syldavia", iso_two_letter="SW")
related = RelatedModel(country=country)
country.save()
RelatedModel.objects.bulk_create([related])
self.assertEqual(related.country_id, country.pk)

def test_unsaved_parent(self):
parent = NoFields()
msg = (
Expand Down
10 changes: 10 additions & 0 deletions tests/test_client/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,16 @@ def test_redirect_with_http_host(self):
)
self.assertEqual(response.content, b"hostname2")

@override_settings(PREPEND_WWW=True, ALLOWED_HOSTS=["testserver", "www.testserver"])
def test_prepend_www_follow_redirect(self):
response = self.client.get("/get_view/", follow=True)
self.assertRedirects(
response,
"http://www.testserver/get_view/",
status_code=301,
target_status_code=200,
)

def test_external_redirect_without_trailing_slash(self):
"""
Client._handle_redirects() with an empty path.
Expand Down
Loading