When retrieving field information from source, if the object retrieved by a chain operation is None, it should be returned directly.
This operation was removed after version 3.6.x, if so I may need to make additional judgment, I think this action is friendly
What do you think?
def get_attribute(instance, attrs):
for attr in attrs:
# Break out early if we get `None` at any point in a nested lookup.
if instance is None:
return None
try:
if isinstance(instance, Mapping):
instance = instance[attr]
else:
instance = getattr(instance, attr)
except ObjectDoesNotExist:
return None
if is_simple_callable(instance):
try:
instance = instance()
except (AttributeError, KeyError) as exc:
# If we raised an Attribute or KeyError here it'd get treated
# as an omitted field in `Field.get_attribute()`. Instead we
# raise a ValueError to ensure the exception is not masked.
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
return instance
def get_attribute(instance, attrs):
for attr in attrs:
try:
if isinstance(instance, Mapping):
instance = instance[attr]
else:
instance = getattr(instance, attr)
except ObjectDoesNotExist:
return None
if is_simple_callable(instance):
try:
instance = instance()
except (AttributeError, KeyError) as exc:
# If we raised an Attribute or KeyError here it'd get treated
# as an omitted field in `Field.get_attribute()`. Instead we
# raise a ValueError to ensure the exception is not masked.
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
return instance
drf version:3.10.x
# models.py
from django.db import models
class B(models.Model):
name = models.CharField(max_length=32)
class A(models.Model):
field1 = models.ForeignKey("B", on_delete=models.CASCADE, null=True)
# serializer.py
class ASerializer(serializers.ModelSerializer):
name = serializers.CharField(source="field1.name")
class Meta:
fields = ("name", )
>>> from . import models
>>> from . import serializer
>>> ins = models.A.objects.create()
>>> ser = serializer.A(ins)
>>> ser.data
...
AttributeError: Got AttributeError when attempting to get a value for field `name` on serializer `ASerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `B` instance.
Original exception text was: 'NoneType' object has no attribute 'name'.
I think the expected behavior is friendly and I will submit a PR if you approve.
Thanks.
It'd be more robust, so yup seems reasonable.
This was removed in #5375 to fix behavior around using default values. In this case, I think what we might want to do here is raise a more informative error message. Something that indicates that the relation was null, and the serializer should provide a default value.
Thanks @rpkilby. I was trying to remember that. 🥇
I saw that check and was just "I remember you..."
ok,I think I know what to do.
I don't think that's stated in the documentation, after the change.
Thanks.
@rpkilby Closing this off then, right?