Fixed #31486 -- Deprecated passing unsaved objects to related filters.
Co-Authored-By: Hasan Ramezani <hasan.r67@gmail.com>
This commit is contained in:
parent
11cc227344
commit
2b6a3baebe
|
@ -1,3 +1,5 @@
|
|||
import warnings
|
||||
|
||||
from django.db.models.lookups import (
|
||||
Exact,
|
||||
GreaterThan,
|
||||
|
@ -7,6 +9,7 @@ from django.db.models.lookups import (
|
|||
LessThan,
|
||||
LessThanOrEqual,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango50Warning
|
||||
|
||||
|
||||
class MultiColSource:
|
||||
|
@ -40,6 +43,15 @@ def get_normalized_value(value, lhs):
|
|||
from django.db.models import Model
|
||||
|
||||
if isinstance(value, Model):
|
||||
if value.pk is None:
|
||||
# When the deprecation ends, replace with:
|
||||
# raise ValueError(
|
||||
# "Model instances passed to related filters must be saved."
|
||||
# )
|
||||
warnings.warn(
|
||||
"Passing unsaved model instances to related filters is deprecated.",
|
||||
RemovedInDjango50Warning,
|
||||
)
|
||||
value_list = []
|
||||
sources = lhs.output_field.path_infos[-1].target_fields
|
||||
for source in sources:
|
||||
|
|
|
@ -85,6 +85,8 @@ details on these changes.
|
|||
objects without providing the ``chunk_size`` argument will no longer be
|
||||
allowed.
|
||||
|
||||
* Passing unsaved model instances to related filters will no longer be allowed.
|
||||
|
||||
.. _deprecation-removed-in-4.1:
|
||||
|
||||
4.1
|
||||
|
|
|
@ -484,6 +484,9 @@ Miscellaneous
|
|||
versions, no prefetching was done. Providing a value for ``chunk_size``
|
||||
signifies that the additional query per chunk needed to prefetch is desired.
|
||||
|
||||
* Passing unsaved model instances to related filters is deprecated. In Django
|
||||
5.0, the exception will be raised.
|
||||
|
||||
Features removed in 4.1
|
||||
=======================
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ from django.db.models.expressions import RawSQL
|
|||
from django.db.models.sql.constants import LOUTER
|
||||
from django.db.models.sql.where import NothingNode, WhereNode
|
||||
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
from django.test.utils import CaptureQueriesContext, ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango50Warning
|
||||
|
||||
from .models import (
|
||||
FK1,
|
||||
|
@ -1899,6 +1900,19 @@ class Queries5Tests(TestCase):
|
|||
self.assertEqual(Ranking.objects.filter(author__in=authors).get(), self.rank3)
|
||||
self.assertEqual(authors.count(), 1)
|
||||
|
||||
def test_filter_unsaved_object(self):
|
||||
# These tests will catch ValueError in Django 5.0 when passing unsaved
|
||||
# model instances to related filters becomes forbidden.
|
||||
# msg = "Model instances passed to related filters must be saved."
|
||||
msg = "Passing unsaved model instances to related filters is deprecated."
|
||||
company = Company.objects.create(name="Django")
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
Employment.objects.filter(employer=Company(name="unsaved"))
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
Employment.objects.filter(employer__in=[company, Company(name="unsaved")])
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
StaffUser.objects.filter(staff=Staff(name="unsaved"))
|
||||
|
||||
|
||||
class SelectRelatedTests(TestCase):
|
||||
def test_tickets_3045_3288(self):
|
||||
|
@ -3211,6 +3225,7 @@ class ExcludeTests(TestCase):
|
|||
[self.j1, self.j2],
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_exclude_unsaved_o2o_object(self):
|
||||
jack = Staff.objects.create(name="jack")
|
||||
jack_staff = StaffUser.objects.create(staff=jack)
|
||||
|
@ -3221,6 +3236,19 @@ class ExcludeTests(TestCase):
|
|||
StaffUser.objects.exclude(staff=unsaved_object), [jack_staff]
|
||||
)
|
||||
|
||||
def test_exclude_unsaved_object(self):
|
||||
# These tests will catch ValueError in Django 5.0 when passing unsaved
|
||||
# model instances to related filters becomes forbidden.
|
||||
# msg = "Model instances passed to related filters must be saved."
|
||||
company = Company.objects.create(name="Django")
|
||||
msg = "Passing unsaved model instances to related filters is deprecated."
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
Employment.objects.exclude(employer=Company(name="unsaved"))
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
Employment.objects.exclude(employer__in=[company, Company(name="unsaved")])
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
StaffUser.objects.exclude(staff=Staff(name="unsaved"))
|
||||
|
||||
|
||||
class ExcludeTest17600(TestCase):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue