Last active
March 1, 2021 04:34
-
-
Save nemesifier/8132696 to your computer and use it in GitHub Desktop.
Django Rest Framework Dynamic relationships mixin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# USAGE EXAMPLE: | |
# https://github.com/nemesisdesign/nodeshot/blob/09d5307fa38861339a660ba96b2c79f9c19ec92a/nodeshot/core/layers/models/__init__.py | |
from django.core.urlresolvers import NoReverseMatch | |
from rest_framework import serializers | |
from rest_framework.fields import Field | |
from rest_framework.reverse import reverse | |
class DynamicRelationshipsMixin(object): | |
""" | |
Django Rest Framework Serializer Mixin | |
which adds the possibility to dynamically add relationships to a serializer. | |
To add a relationship, use the class method "add_relationship", this way: | |
>>> SerializerName.add_relationship('relationship_name', 'view_name', 'lookup_field') | |
for example: | |
>>> from nodeshot.core.nodes.serializers import NodeDetailSerializer | |
>>> NodeDetailSerializer.add_relationship(**{ | |
'name': 'comments', | |
'view_name': 'api_node_comments', | |
'lookup_field': 'slug' | |
}) | |
""" | |
_relationships = {} | |
@classmethod | |
def add_relationship(_class, name, view_name, lookup_field): | |
""" adds a relationship to serializer | |
:param name: relationship name (dictionary key) | |
:type name: str | |
:param view_name: view name as specified in urls.py | |
:type view_name: str | |
:param lookup_field: lookup field, usually slug or id/pk | |
:type lookup_field: str | |
:returns: None | |
""" | |
_class._relationships[name] = (view_name, lookup_field) | |
def get_lookup_value(self, obj, string): | |
if '.' in string: | |
levels = string.split('.') | |
value = getattr(obj, levels.pop(0)) | |
if value is not None: | |
for level in levels: | |
value = getattr(value, level) | |
return value | |
else: | |
return None | |
else: | |
return getattr(obj, string) | |
def get_relationships(self, obj): | |
request = self.context['request'] | |
format = self.context['format'] | |
relationships = {} | |
# loop over private _relationship attribute | |
for key, value in self._relationships.iteritems(): | |
# retrieve view_name and name of lookup field by splitting tuple | |
view_name, lookup_field = value | |
lookup_value = self.get_lookup_value(obj, lookup_field) | |
# populate new dictionary with links | |
relationships[key] = reverse(view_name, | |
args=[lookup_value], | |
request=request, | |
format=format) | |
return relationships |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This looks really cool! i wonder, is there any way to specify the type of relationship? I would like to add HyperlinkRelatedFields in that manner. Maybe my understanding of the inner workings of Django is not good enough, but is that possible?