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",
|
"concrete_fields",
|
||||||
"local_concrete_fields",
|
"local_concrete_fields",
|
||||||
"_non_pk_concrete_field_names",
|
"_non_pk_concrete_field_names",
|
||||||
|
"_reverse_one_to_one_field_names",
|
||||||
"_forward_fields_map",
|
"_forward_fields_map",
|
||||||
"managers",
|
"managers",
|
||||||
"managers_map",
|
"managers_map",
|
||||||
|
@ -992,6 +993,16 @@ class Options:
|
||||||
names.append(field.attname)
|
names.append(field.attname)
|
||||||
return frozenset(names)
|
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
|
@cached_property
|
||||||
def db_returning_fields(self):
|
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
|
Create a new object with the given kwargs, saving it to the database
|
||||||
and returning the created object.
|
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)
|
obj = self.model(**kwargs)
|
||||||
self._for_write = True
|
self._for_write = True
|
||||||
obj.save(force_insert=True, using=self.db)
|
obj.save(force_insert=True, using=self.db)
|
||||||
|
|
|
@ -524,6 +524,29 @@ class OneToOneTests(TestCase):
|
||||||
Director._meta.base_manager_name = None
|
Director._meta.base_manager_name = None
|
||||||
Director._meta._expire_cache()
|
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):
|
def test_hasattr_related_object(self):
|
||||||
# The exception raised on attribute access when a related object
|
# The exception raised on attribute access when a related object
|
||||||
# doesn't exist should be an instance of a subclass of `AttributeError`
|
# doesn't exist should be an instance of a subclass of `AttributeError`
|
||||||
|
|
Loading…
Reference in New Issue