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

Fixed #24716 -- Deprecated Field._get_val_from_obj() #4562

Closed
wants to merge 1 commit into from

Conversation

ovangle
Copy link
Contributor

@ovangle ovangle commented Apr 26, 2015

The method duplicates the functionality of Field.value_from_object
and has the additional downside of being a privately named public
API method.

All usage of the method in django.* libraries have been replaced
with a call to getattr, to reduce the overhead of an additional,
unecessary function call.

No unittests are added, since this is just the removal of a single method,
which was already amply tested by the serialization tests.

@timgraham
Copy link
Member

It doesn't seem best to me to recommend using value_from_object() in the docs but use getattr in the code. Yes, we avoid a function call, but it may make the fields less extensible. It would be great if we could test some third-party fields and see how they are affected by the change.

There is also the issue that if a custom field is overriding _get_val_from_obj() it will no longer be called in all the places Django makes use of it.

Please see the Deprecating a Feature checklist. In particular, we need documentation. A Trac ticket should also be created to track the change. Thanks.

@ovangle
Copy link
Contributor Author

ovangle commented Apr 27, 2015

I fail to see how it makes anything less extensible -- _get_val_from_obj was never a hook to customise attribute access and it was only ever called by the various implementations of value_to_string. There is nothing you could customise by overriding it that you couldn't already implement as part of value_to_string.

I wanted to remove value_from_object and save_form_data as well (which is why I reimplemented using getattr) for redundancy reasons, but figured some people might think that having an alternative to getattr/setattr is more friendly to new users. Which it is, and they don't suffer from the additional problem of having "private" method names.

As far as the discrepancy between the documentation and the implementation goes, getattr is more consistent with the rest of the django.models.fields package. The micro-optimisation of the additional function call saves nothing, since django is IO bound.

Trac ticket #24716
I've also added deprecation details to the relevant release documentation.

@ovangle ovangle changed the title Cleanup: Deprecate Field._get_val_from_obj Fix #24716: Deprecate Field._get_val_from_obj Apr 27, 2015
@timgraham
Copy link
Member

Here are examples of people overriding _get_val_from_obj(). Maybe it's okay to break backwards compatibility if the gains are sufficient, but if so, we need to document how to adapt existing code that does so.

https://github.com/search?utf8=%E2%9C%93&q=%22def+_get_val_from_obj%22&type=Code&ref=searchresults

@ovangle
Copy link
Contributor Author

ovangle commented Apr 29, 2015

I took a quick browse through the first page of results, they're all identical, copy_pasted from appengine_django, and none of them override _get_val_from_obj, they ducktype it out. All of them also ducktype value_to_string, so they can't be calling _get_val_from_obj anywhere anyway.

Whether the "gains" are clear enough, I can't say. As it stands there are two identical methods which both do exactly the same (useless and redundant) thing, one of which is (unfortunately) named as a private method and should be removed.

The migration path is simple -- rename all calls to _get_val_from_obj with value_from_object. It's right there in both the deprecation warnings and is pretty damn straightforward.

@ovangle
Copy link
Contributor Author

ovangle commented Apr 29, 2015

And just looked through the next five pages of results. All exactly the same c+v code. Why the hell do people do that? Argh.

@@ -58,6 +58,8 @@ details on these changes.
* The ``django.template.loaders.base.Loader.__call__()`` method will be
removed.

* ``Field._get_val_from_obj()`` will be renamed to ``Field.value_from_object()``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will be removed

@timgraham
Copy link
Member

I think using value_from_object() rather than getattr() results in better readability. Especially since people may copy from Django's fields, I would still prefer to follow the documentation and use that method in our custom fields.

@timgraham timgraham changed the title Fix #24716: Deprecate Field._get_val_from_obj Fixed #24716 -- Deprecated Field._get_val_from_obj() May 4, 2015
@ovangle
Copy link
Contributor Author

ovangle commented May 4, 2015

I understand that, but internal consistency and readability is important too. 99% of all field values are fetched using getattr within the django.db.fields api. It took me a while when looking into the code when I first started working on the composite fields stuff to realise that _get_val_from_obj and value_from_object did absolutely nothing special.

(which incidentally, is the reason I wanted to change it in the first place -- readability).

And what does it matter if the user c+vs the getattr method for attribute access from django core code? It's identical to the method call and getattr should be readable enough for anybody who knows the python builtins and their semantics.

getattr(model, field.attname)

"Get the attribute from the model, using the attname of the field". Pretty readable as far as I'm concerned. Using field.attname rather than field.name is the only slightly confusing part. But I'm hoping that we will be able to remove the name vs. attname distinction once the composite fields work is done (but that isn't planned as part of the initial work).

@timgraham
Copy link
Member

I guess I would be less averse if Field.attname were formally documented. "Field attribute reference" in docs/ref/models/fields.txt seems like a good place.

The method duplicates the functionality of `Field.value_from_object`
and has the additional downside of being a privately named public
API method.

All usage of the method in django.* libraries have been replaced
with a call to getattr, to reduce the overhead of an additional,
unecessary function call.
@ovangle ovangle force-pushed the deprecate_get_val_from_obj branch from 6654cc5 to 06d1ab8 Compare May 17, 2015 10:06
@ovangle
Copy link
Contributor Author

ovangle commented May 17, 2015

I made the suggested documentation changes and documented Field.attname. I've left custom-model-fields.txt (largely) as is, because I do think that code outside the fields package should use value_from_object.

@ovangle ovangle closed this May 22, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants