Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax redundant method name restriction for SerializerMethodField #2420

Closed
gtaylor opened this issue Jan 14, 2015 · 14 comments · Fixed by #6767
Closed

Relax redundant method name restriction for SerializerMethodField #2420

gtaylor opened this issue Jan 14, 2015 · 14 comments · Fixed by #6767
Assignees

Comments

@gtaylor
Copy link

gtaylor commented Jan 14, 2015

As per the 3.0 release, we now get AssertionErrors if we pass in a method name that matches the default:

AssertionError: It is redundant to specify `get_id_salted` on SerializerMethodField 'id_salted' in serializer 'UserSerializer', because it is the same as the default method name. Remove the `method_name` argument.

I can certainly see an argument for this sort of thing, but I subjectively prefer to be as explicit as possible, even if it comes at the cost of a few extra keystrokes. At any time, our team has external contractors (who may or may not have worked with DRF before) coming in and out, so this is one of those little easy hints we can give them. That arg (even if it's not needed anymore) provides some additional context for someone who is getting their bearings.

Would you accept a PR with a setting to disable this assertion? It'd help with those of us who prefer to be very explicit, and would also improve the migration path for those who don't care to make this change for many hundreds of serializer fields in larger codebases.

@tomchristie
Copy link
Member

Would you accept a PR with a setting to disable this assertion?

No I don't think we should have it as a setting. We could reconsider the check tho.

@gtaylor
Copy link
Author

gtaylor commented Jan 14, 2015

Is there anything I can do to help with that?

I'm sure there are others that enshrine "Explicit is better than implicit" as much as I do. I feel like Django is heading in the direction of being more explicit over time, too (starting with the days of magic-removal).

@tomchristie
Copy link
Member

Is there anything I can do to help with that?

You may as well issue the PR removing it, check if there's any tests expecting the assertion error that now fail, and also in the same PR update/remove any bits of docs that mention it, eg the 3.0 announcement.

@tomchristie tomchristie changed the title (Optionally?) allow more explicit SerializerMethodField arg Allow more explicit SerializerMethodField arg Jan 15, 2015
@tomchristie tomchristie added this to the 3.0.4 Release milestone Jan 15, 2015
@gtaylor
Copy link
Author

gtaylor commented Jan 15, 2015

Done! See the PR and make sure you are OK with this assert being removed from the Field parent class. I don't think there's a great reason to pass a redundant source param to something like a CharField, but I'm not sure we'd want to police that and not SMField. Seems like that could be handled by the users of DRF during their code reviews. I suppose there's still a case like this where it could be funky looking:

some_field = CharField(source='doesnt_match')
# Looks kind of out of place?
matching_field = CharField()
another_field = CharField(source='doesnt_match_either')

@tomchristie
Copy link
Member

Seems like that could be handled by the users of DRF during their code reviews.

No - I've seen it plenty of times in 2.x codebases, and it's harmful to the ecosystem as it spreads uncertainty about if it's required or not. We can consider SerializerMethodField, but I'd def be against this change for source.

@gtaylor
Copy link
Author

gtaylor commented Jan 15, 2015

How would you like to handle the exemption for SMField but not Field? We'd need to disable the check, and I imagine we'd want to avoid messing with the signature of bind(). Would a (private?) class variable be OK? Could override in sub-classes to give people easy control over this behavior in custom fields.

@tomchristie
Copy link
Member

They're different checks. Don't affect each other. I'm still not totally convinced this change is something we want tho, enforced consistency is def a good thing.

@gtaylor
Copy link
Author

gtaylor commented Jan 15, 2015

Maybe I'm reading this wrong, but I think the assertion check would come up from the parent class (Field) here: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/fields.py#L1237

Wouldn't we need to suppress that?

@tomchristie
Copy link
Member

On reflection I'm going to close this off. The behaviour as it currently stands is deliberate design and I'm happy with the benefit of enforcing a single consistent style.

@masterpi314
Copy link

I just ran into this on a case you're probably not considering: the source argument is coming from a lookup in a global dictionary that is used in other places. The dictionary currently contains mostly identity mappings, but my serializer should respect that dictionary should it ever change. I can't do that right now without jumping through major hoops because of this assertion, which is totally unnecessary to the functioning of this class. I don't honestly care if you remove it or not because I won't be able to use the new version before it matters, but IMO this is an ill-considered design decision.

@rpkilby
Copy link
Member

rpkilby commented Dec 3, 2018

Hi @masterpi314. It's difficult to appreciate your use case without seeing a more complete example. e.g., it's not clear if there's another way to workaround your issue. Regardless, it shouldn't be too difficult to override the bind method to exhibit the desired behavior.

Just make sure that you call super(SerializerMethodField, self).bind(field_name, parent), to skip SerializerMethodField's bind implementation.

@ghost
Copy link

ghost commented Jun 20, 2019

The implicit relationship between a SerializerMethodField and a method means that the code is harder to read than specifying method_name=get_whatever.__name__. Specifying the method name like this also means refactoring tools can rename the method. My team is literally working around this by renaming getter methods.

Please reconsider disabling this assertion. Would you be willing to accept a similar PR for only this change?

Apropos: Have you considered just having a method argument rather than method_name?

@rpkilby
Copy link
Member

rpkilby commented Jun 20, 2019

I am +0 on relaxing this restriction. On the one hand, I understand that consistency is valuable - it would be undesirable if redundant method names are provided inconsistently. On the other hand, I also prefer explicitly providing the method name, even if it does happen to be redundant.

I'll leave this to Tom, but if this isn't accepted, a minimal implementation to require a method is:

class SerializerMethodField(serializers.Field):
    def __init__(self, method, **kwargs):
        self.method = method
        kwargs['source'] = '*'
        kwargs['read_only'] = True
        super().__init__(**kwargs)

    def to_representation(self, value):
        method = getattr(self.parent, self.method)
        return method(value)

@tomchristie
Copy link
Member

Ran into this working with a client. Probably would be okay with us relaxing the source assertion.

@rpkilby rpkilby reopened this Jun 21, 2019
@rpkilby rpkilby changed the title Allow more explicit SerializerMethodField arg Relax redundant method name restriction for SerializerMethodField Jun 21, 2019
@rpkilby rpkilby self-assigned this Jun 28, 2019
stianjensen added a commit to stianjensen/djangorestframework-stubs that referenced this issue Jan 6, 2022
https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

You can leave the method_name parameter empty, to get a default value.

For a long time, drf even gave an error when you provided a parameter that matched `get_` your field name:
encode/django-rest-framework#2420
stianjensen added a commit to stianjensen/djangorestframework-stubs that referenced this issue Mar 31, 2022
https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

You can leave the method_name parameter empty, to get a default value.

For a long time, drf even gave an error when you provided a parameter that matched `get_` your field name:
encode/django-rest-framework#2420
sobolevn pushed a commit to typeddjango/djangorestframework-stubs that referenced this issue Apr 1, 2022
https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

You can leave the method_name parameter empty, to get a default value.

For a long time, drf even gave an error when you provided a parameter that matched `get_` your field name:
encode/django-rest-framework#2420
XF-FW pushed a commit to XF-FW/djangorestframework-stubs that referenced this issue Apr 7, 2022
https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

You can leave the method_name parameter empty, to get a default value.

For a long time, drf even gave an error when you provided a parameter that matched `get_` your field name:
encode/django-rest-framework#2420
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants