Skip to content

Commit

Permalink
Create a default implementation of Model.natural_key().
Browse files Browse the repository at this point in the history
  • Loading branch information
jianli committed May 6, 2014
1 parent df60db0 commit b6d644b
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
38 changes: 38 additions & 0 deletions django/db/models/base.py
Expand Up @@ -1409,6 +1409,44 @@ def _check_ordering(cls):
)
return errors

@classmethod
def _natural_key_fieldnames(cls):
"""
Helper method for model.natural_key and manager.get_by_natural_key.
The fieldnames follow Django's double-underscore notation.
If no suitable fieldnames are found, the method will return an
empty sequence.
"""
if cls._meta.unique_together:
unique_fieldnames = cls._meta.unique_together[0]
else:
unique_fieldnames = [
f.name for f in cls._meta.fields
if f.unique and not f.auto_created
]
natural_key_fieldnames = []
for field_name in unique_fieldnames:
field, _, _, _ = cls._meta.get_field_by_name(field_name)
if not field.rel:
natural_key_fieldnames.append(field.name)
else:
natural_key_fieldnames.extend(
'%s__%s' % (field.name, i) for i in
field.rel.to._natural_key_fieldnames()
)
return natural_key_fieldnames

def natural_key(self):
fieldnames = self.__class__._natural_key_fieldnames()
if not fieldnames:
raise NotImplementedError(
'The %s class must provide a natural_key() method.' %
self.__class__.__name__
)
return tuple(reduce(getattr, f.split('__'), self) for f in fieldnames)


############################################
# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
Expand Down
3 changes: 3 additions & 0 deletions django/db/models/manager.py
Expand Up @@ -73,6 +73,9 @@ def __str__(self):
def check(self, **kwargs):
return []

def get_by_natural_key(self, *args):
return self.get(**dict(zip(self.model._natural_key_fieldnames(), args)))

@classmethod
def _get_queryset_methods(cls, queryset_class):
def create_method(name, method):
Expand Down

0 comments on commit b6d644b

Please sign in to comment.