Enhancement dont require pk strictly related #2745 by bleib1dj · Pull Request #2754 · encode/django-rest-framework (original) (raw)

Rationale

I implemented the enhancement with the id_field to provide users using non-django ORM backends the ability to still utilize the check originally provided by if obj.pk is None, prior to providing a related reference. I believe this gives more flexibility but also potentially provides unnecessary functionality as alternative backends may not generate an identification value solely upon storage and could potentially have their identifier provided prior to save. If the backend does that this check would only serve to verify that the user properly assigned an identifier but would not provide the intended affect of verifying the object has been created. That being said, there is the potential for this to also be done with the django ORM as the following example illustrates:

from django.contrib.auth.models import User
from uuid import uuid1

new_uuid = str(uuid1())
my_user = User(pk=new_uuid, email="this@email.com", username="test_user")
print my_user.pk
query_user = User.objects.get(pk=new_uuid)
Out: '5412f4cc-d166-11e4-b274-080027a2dd8c'
Out: DoesNotExist: User matching query does not exist

This goes against using User.objects.create(...) but could be done. In either case providing the id_field gives the user the ability to choose, where hasattr() limits the check to only working when the pk attribute is present.

If this way of handling the enhancement is agreed upon I can add additional docs detailing the optional field and when to utilize it. Otherwise we can close out this PR and I can open one with my hassattr() modifications instead.

Additional references

Per our discussion in #2745 I found a couple additional locations of pk attribute references.

PrimaryKeyRelatedField

There's a reference in the to_representation method but I opted not to change it as I believe the SlugField provides a way of achieving this functionality for a non-django ORM based backend.

ManyRelatedField

There was a reference in the get_attribute method that I swapped out with self.id_field which also required the definition of self.id_field within it's own __init__ method.

I chose to define it there rather than up in the Field class as the ManyRelatedField is "Automagically" created in the RelatedField and passed its kwargs. So instead of giving users the ability to set an id_field on every field, which would be unnecessary, this should reduce it to them only needing to set it on the HyperlinkedRelatedField and HyperlinkedIdentityField if they choose to, while still supporting many=True.