mirror of https://github.com/django/django.git
Fixed #34586 -- Made QuerySet.create() raise ValueError for reverse one-to-many relations.
This commit is contained in:
parent
aa3cb3f372
commit
e02fc58889
|
@ -90,6 +90,7 @@ class Options:
|
|||
"concrete_fields",
|
||||
"local_concrete_fields",
|
||||
"_non_pk_concrete_field_names",
|
||||
"_reverse_one_to_one_field_names",
|
||||
"_forward_fields_map",
|
||||
"managers",
|
||||
"managers_map",
|
||||
|
@ -992,6 +993,16 @@ class Options:
|
|||
names.append(field.attname)
|
||||
return frozenset(names)
|
||||
|
||||
@cached_property
|
||||
def _reverse_one_to_one_field_names(self):
|
||||
"""
|
||||
Return a set of reverse one to one field names pointing to the current
|
||||
model.
|
||||
"""
|
||||
return frozenset(
|
||||
field.name for field in self.related_objects if field.one_to_one
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def db_returning_fields(self):
|
||||
"""
|
||||
|
|
|
@ -662,6 +662,15 @@ class QuerySet(AltersData):
|
|||
Create a new object with the given kwargs, saving it to the database
|
||||
and returning the created object.
|
||||
"""
|
||||
reverse_one_to_one_fields = frozenset(kwargs).intersection(
|
||||
self.model._meta._reverse_one_to_one_field_names
|
||||
)
|
||||
if reverse_one_to_one_fields:
|
||||
raise ValueError(
|
||||
"The following fields do not exist in this model: %s"
|
||||
% ", ".join(reverse_one_to_one_fields)
|
||||
)
|
||||
|
||||
obj = self.model(**kwargs)
|
||||
self._for_write = True
|
||||
obj.save(force_insert=True, using=self.db)
|
||||
|
|
|
@ -524,6 +524,29 @@ class OneToOneTests(TestCase):
|
|||
Director._meta.base_manager_name = None
|
||||
Director._meta._expire_cache()
|
||||
|
||||
def test_create_reverse_o2o_error(self):
|
||||
msg = "The following fields do not exist in this model: restaurant"
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
Place.objects.create(restaurant=self.r1)
|
||||
|
||||
def test_get_or_create_reverse_o2o_error(self):
|
||||
msg = "The following fields do not exist in this model: restaurant"
|
||||
r2 = Restaurant.objects.create(
|
||||
place=self.p2, serves_hot_dogs=True, serves_pizza=False
|
||||
)
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
Place.objects.get_or_create(name="nonexistent", defaults={"restaurant": r2})
|
||||
|
||||
def test_update_or_create_reverse_o2o_error(self):
|
||||
msg = "The following fields do not exist in this model: restaurant"
|
||||
r2 = Restaurant.objects.create(
|
||||
place=self.p2, serves_hot_dogs=True, serves_pizza=False
|
||||
)
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
Place.objects.update_or_create(
|
||||
name="nonexistent", defaults={"restaurant": r2}
|
||||
)
|
||||
|
||||
def test_hasattr_related_object(self):
|
||||
# The exception raised on attribute access when a related object
|
||||
# doesn't exist should be an instance of a subclass of `AttributeError`
|
||||
|
|
Loading…
Reference in New Issue