[1.8.x] Fixed #24289 -- Reversed usage of Field.many_to_one and one_to_many.
Thanks Carl Meyer and Tim Graham for the reviews and to all involved
in the discussion.
Backport of 18c0aaa912
from master
This commit is contained in:
parent
136edac897
commit
20b621eb3c
|
@ -296,7 +296,7 @@ def _get_non_gfk_field(opts, name):
|
||||||
"not found" by get_field(). This could likely be cleaned up.
|
"not found" by get_field(). This could likely be cleaned up.
|
||||||
"""
|
"""
|
||||||
field = opts.get_field(name)
|
field = opts.get_field(name)
|
||||||
if field.is_relation and field.one_to_many and not field.related_model:
|
if field.is_relation and field.many_to_one and not field.related_model:
|
||||||
raise FieldDoesNotExist()
|
raise FieldDoesNotExist()
|
||||||
return field
|
return field
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ class GenericForeignKey(object):
|
||||||
|
|
||||||
is_relation = True
|
is_relation = True
|
||||||
many_to_many = False
|
many_to_many = False
|
||||||
many_to_one = False
|
many_to_one = True
|
||||||
one_to_many = True
|
one_to_many = False
|
||||||
one_to_one = False
|
one_to_one = False
|
||||||
related_model = None
|
related_model = None
|
||||||
|
|
||||||
|
@ -258,8 +258,8 @@ class GenericRelation(ForeignObject):
|
||||||
auto_created = False
|
auto_created = False
|
||||||
|
|
||||||
many_to_many = False
|
many_to_many = False
|
||||||
many_to_one = True
|
many_to_one = False
|
||||||
one_to_many = False
|
one_to_many = True
|
||||||
one_to_one = False
|
one_to_one = False
|
||||||
|
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
|
|
|
@ -65,7 +65,7 @@ def get_candidate_relations_to_delete(opts):
|
||||||
# N-N (i.e., many-to-many) relations aren't candidates for deletion.
|
# N-N (i.e., many-to-many) relations aren't candidates for deletion.
|
||||||
return (
|
return (
|
||||||
f for f in candidate_model_fields
|
f for f in candidate_model_fields
|
||||||
if f.auto_created and not f.concrete and (f.one_to_one or f.many_to_one)
|
if f.auto_created and not f.concrete and (f.one_to_one or f.one_to_many)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1475,8 +1475,8 @@ class ManyToManyRel(ForeignObjectRel):
|
||||||
class ForeignObject(RelatedField):
|
class ForeignObject(RelatedField):
|
||||||
# Field flags
|
# Field flags
|
||||||
many_to_many = False
|
many_to_many = False
|
||||||
many_to_one = False
|
many_to_one = True
|
||||||
one_to_many = True
|
one_to_many = False
|
||||||
one_to_one = False
|
one_to_one = False
|
||||||
|
|
||||||
requires_unique_target = True
|
requires_unique_target = True
|
||||||
|
@ -1785,8 +1785,8 @@ class ForeignObject(RelatedField):
|
||||||
class ForeignKey(ForeignObject):
|
class ForeignKey(ForeignObject):
|
||||||
# Field flags
|
# Field flags
|
||||||
many_to_many = False
|
many_to_many = False
|
||||||
many_to_one = False
|
many_to_one = True
|
||||||
one_to_many = True
|
one_to_many = False
|
||||||
one_to_one = False
|
one_to_one = False
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
|
@ -388,9 +388,9 @@ class Options(object):
|
||||||
# and all the models may not have been loaded yet; we don't want to cache
|
# and all the models may not have been loaded yet; we don't want to cache
|
||||||
# the string reference to the related_model.
|
# the string reference to the related_model.
|
||||||
is_not_an_m2m_field = lambda f: not (f.is_relation and f.many_to_many)
|
is_not_an_m2m_field = lambda f: not (f.is_relation and f.many_to_many)
|
||||||
is_not_a_generic_relation = lambda f: not (f.is_relation and f.many_to_one)
|
is_not_a_generic_relation = lambda f: not (f.is_relation and f.one_to_many)
|
||||||
is_not_a_generic_foreign_key = lambda f: not (
|
is_not_a_generic_foreign_key = lambda f: not (
|
||||||
f.is_relation and f.one_to_many and not (hasattr(f.rel, 'to') and f.rel.to)
|
f.is_relation and f.many_to_one and not (hasattr(f.rel, 'to') and f.rel.to)
|
||||||
)
|
)
|
||||||
return make_immutable_fields_list(
|
return make_immutable_fields_list(
|
||||||
"fields",
|
"fields",
|
||||||
|
@ -564,7 +564,7 @@ class Options(object):
|
||||||
for field in fields:
|
for field in fields:
|
||||||
# For backwards compatibility GenericForeignKey should not be
|
# For backwards compatibility GenericForeignKey should not be
|
||||||
# included in the results.
|
# included in the results.
|
||||||
if field.is_relation and field.one_to_many and field.related_model is None:
|
if field.is_relation and field.many_to_one and field.related_model is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
names.add(field.name)
|
names.add(field.name)
|
||||||
|
|
|
@ -1863,16 +1863,6 @@ relation. These attribute are present on all fields; however, they will only
|
||||||
have meaningful values if the field is a relation type
|
have meaningful values if the field is a relation type
|
||||||
(:attr:`Field.is_relation=True <Field.is_relation>`).
|
(:attr:`Field.is_relation=True <Field.is_relation>`).
|
||||||
|
|
||||||
.. attribute:: Field.one_to_many
|
|
||||||
|
|
||||||
Boolean flag that is ``True`` if the field has a one-to-many relation, such
|
|
||||||
as a ``ForeignKey``; ``False`` otherwise.
|
|
||||||
|
|
||||||
.. attribute:: Field.one_to_one
|
|
||||||
|
|
||||||
Boolean flag that is ``True`` if the field has a one-to-one relation, such
|
|
||||||
as a ``OneToOneField``; ``False`` otherwise.
|
|
||||||
|
|
||||||
.. attribute:: Field.many_to_many
|
.. attribute:: Field.many_to_many
|
||||||
|
|
||||||
Boolean flag that is ``True`` if the field has a many-to-many relation;
|
Boolean flag that is ``True`` if the field has a many-to-many relation;
|
||||||
|
@ -1882,9 +1872,19 @@ have meaningful values if the field is a relation type
|
||||||
.. attribute:: Field.many_to_one
|
.. attribute:: Field.many_to_one
|
||||||
|
|
||||||
Boolean flag that is ``True`` if the field has a many-to-one relation, such
|
Boolean flag that is ``True`` if the field has a many-to-one relation, such
|
||||||
|
as a ``ForeignKey``; ``False`` otherwise.
|
||||||
|
|
||||||
|
.. attribute:: Field.one_to_many
|
||||||
|
|
||||||
|
Boolean flag that is ``True`` if the field has a one-to-many relation, such
|
||||||
as a ``GenericRelation`` or the reverse of a ``ForeignKey``; ``False``
|
as a ``GenericRelation`` or the reverse of a ``ForeignKey``; ``False``
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
.. attribute:: Field.one_to_one
|
||||||
|
|
||||||
|
Boolean flag that is ``True`` if the field has a one-to-one relation, such
|
||||||
|
as a ``OneToOneField``; ``False`` otherwise.
|
||||||
|
|
||||||
.. attribute:: Field.related_model
|
.. attribute:: Field.related_model
|
||||||
|
|
||||||
Points to the model the field relates to. For example, ``Author`` in
|
Points to the model the field relates to. For example, ``Author`` in
|
||||||
|
|
|
@ -213,7 +213,7 @@ can be made to convert your code to the new API:
|
||||||
for f in MyModel._meta.get_fields()
|
for f in MyModel._meta.get_fields()
|
||||||
if not f.is_relation
|
if not f.is_relation
|
||||||
or f.one_to_one
|
or f.one_to_one
|
||||||
or (f.one_to_many and f.related_model)
|
or (f.many_to_one and f.related_model)
|
||||||
]
|
]
|
||||||
|
|
||||||
* ``MyModel._meta.get_concrete_fields_with_model()``::
|
* ``MyModel._meta.get_concrete_fields_with_model()``::
|
||||||
|
@ -224,7 +224,7 @@ can be made to convert your code to the new API:
|
||||||
if f.concrete and (
|
if f.concrete and (
|
||||||
not f.is_relation
|
not f.is_relation
|
||||||
or f.one_to_one
|
or f.one_to_one
|
||||||
or (f.one_to_many and f.related_model)
|
or (f.many_to_one and f.related_model)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ can be made to convert your code to the new API:
|
||||||
|
|
||||||
[
|
[
|
||||||
f for f in MyModel._meta.get_fields()
|
f for f in MyModel._meta.get_fields()
|
||||||
if f.many_to_one and f.auto_created
|
if f.one_to_many and f.auto_created
|
||||||
]
|
]
|
||||||
|
|
||||||
* ``MyModel._meta.get_all_related_objects_with_model()``::
|
* ``MyModel._meta.get_all_related_objects_with_model()``::
|
||||||
|
@ -248,7 +248,7 @@ can be made to convert your code to the new API:
|
||||||
[
|
[
|
||||||
(f, f.model if f.model != MyModel else None)
|
(f, f.model if f.model != MyModel else None)
|
||||||
for f in MyModel._meta.get_fields()
|
for f in MyModel._meta.get_fields()
|
||||||
if f.many_to_one and f.auto_created
|
if f.one_to_many and f.auto_created
|
||||||
]
|
]
|
||||||
|
|
||||||
* ``MyModel._meta.get_all_related_many_to_many_objects()``::
|
* ``MyModel._meta.get_all_related_many_to_many_objects()``::
|
||||||
|
@ -274,7 +274,7 @@ can be made to convert your code to the new API:
|
||||||
for field in MyModel._meta.get_fields()
|
for field in MyModel._meta.get_fields()
|
||||||
# For complete backwards compatibility, you may want to exclude
|
# For complete backwards compatibility, you may want to exclude
|
||||||
# GenericForeignKey from the results.
|
# GenericForeignKey from the results.
|
||||||
if not (field.one_to_many and field.related_model is None)
|
if not (field.many_to_one and field.related_model is None)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
This provides a 100% backwards compatible replacement, ensuring that both
|
This provides a 100% backwards compatible replacement, ensuring that both
|
||||||
|
|
|
@ -31,22 +31,22 @@ RELATION_FIELDS = (
|
||||||
GenericRelation,
|
GenericRelation,
|
||||||
)
|
)
|
||||||
|
|
||||||
ONE_TO_MANY_CLASSES = {
|
MANY_TO_MANY_CLASSES = {
|
||||||
|
ManyToManyField,
|
||||||
|
}
|
||||||
|
|
||||||
|
MANY_TO_ONE_CLASSES = {
|
||||||
ForeignObject,
|
ForeignObject,
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
GenericForeignKey,
|
GenericForeignKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
MANY_TO_ONE_CLASSES = {
|
ONE_TO_MANY_CLASSES = {
|
||||||
ForeignObjectRel,
|
ForeignObjectRel,
|
||||||
ManyToOneRel,
|
ManyToOneRel,
|
||||||
GenericRelation,
|
GenericRelation,
|
||||||
}
|
}
|
||||||
|
|
||||||
MANY_TO_MANY_CLASSES = {
|
|
||||||
ManyToManyField,
|
|
||||||
}
|
|
||||||
|
|
||||||
ONE_TO_ONE_CLASSES = {
|
ONE_TO_ONE_CLASSES = {
|
||||||
OneToOneField,
|
OneToOneField,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue