Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

DynamicRelationshipsMixin

  • Loading branch information...
commit be1148fc72885393fa54cb62cce71128efb16b9d 1 parent 60c137b
nemesisdesign authored
8 nodeshot/community/notifications/tests.py
View
@@ -41,10 +41,6 @@ class TestNotification(BaseTestCase):
'test_status.json',
]
- #def setUp(self):
- # # disable web sockets registrars
- # settings.NODESHOT['WEBSOCKETS']['REGISTRARS'] = []
-
def test_notification_to_herself(self):
""" An user cannot send a notification to herself/himself """
n = Notification(
@@ -113,8 +109,8 @@ def test_check_settings(self):
"to_user_id": 4,
"type": "your_node_status_changed",
})
- self.assertTrue(n.check_user_settings(medium='web'))
- self.assertTrue(n.check_user_settings(medium='email'))
+ self.assertEqual(n.check_user_settings(medium='web'), settings.NODESHOT['DEFAULTS']['NOTIFICATION_BOOLEAN_FIELDS'])
+ self.assertTrue(n.check_user_settings(medium='email'), settings.NODESHOT['DEFAULTS']['NOTIFICATION_BOOLEAN_FIELDS'])
def test_node_created_to_all(self):
# set every user to receive notifications about any node created
11 nodeshot/community/participation/models/__init__.py
View
@@ -100,6 +100,17 @@ def _node_participation_settings(self):
Node.participation_settings = _node_participation_settings
+# ------ Add relationship to NodeDetailSerializer ------ #
+
+from nodeshot.core.nodes.serializers import NodeDetailSerializer
+
+NodeDetailSerializer.add_relationship(**{
+ 'name': 'comments',
+ 'view_name': 'api_node_comments',
+ 'lookup_field': 'slug'
+})
+
+
# ------ SIGNALS ------ #
63 nodeshot/core/base/serializers.py
View
@@ -53,6 +53,69 @@ def to_native(self, obj):
return ret
+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))
+ for level in levels:
+ value = getattr(value, level)
+ return value
+ 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
+ # retrieve value with getattr()
+ #string = 'obj.%s' % lookup_field
+ 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
+
+
class HyperlinkedField(Field):
"""
Represents the instance, or a property on the instance, using hyperlinking.
27 nodeshot/core/nodes/serializers.py
View
@@ -5,11 +5,11 @@
from rest_framework.reverse import reverse
from rest_framework_gis import serializers as geoserializers
+from nodeshot.core.base.serializers import DynamicRelationshipsMixin
from nodeshot.core.layers.models import Layer
from .models import *
-PARTICIPATION_INSTALLED = 'nodeshot.community.participation' in settings.NODESHOT['API']['APPS_ENABLED']
HSTORE_ENABLED = settings.NODESHOT['SETTINGS'].get('HSTORE', True)
if HSTORE_ENABLED:
@@ -29,24 +29,28 @@
]
-class NodeDetailSerializer(geoserializers.GeoModelSerializer):
+class NodeDetailSerializer(DynamicRelationshipsMixin, geoserializers.GeoModelSerializer):
""" node detail """
user = serializers.Field(source='user.username')
status = serializers.Field(source='status.slug')
geometry = geoserializers.GeometryField(label=_('coordinates'))
layer_name = serializers.Field(source='layer.name')
- layer_details = serializers.HyperlinkedRelatedField(view_name='api_layer_detail', source='layer', read_only=True)
- images = serializers.HyperlinkedIdentityField(view_name='api_node_images', slug_field='slug')
access_level = serializers.Field(source='get_access_level_display')
+ relationships = serializers.SerializerMethodField('get_relationships')
if HSTORE_ENABLED:
data = HStoreDictionaryField(required=False,
label=_('extra data'),
help_text=_('store extra attributes in JSON string'))
-
- if PARTICIPATION_INSTALLED:
- comments = serializers.HyperlinkedIdentityField(view_name='api_node_comments',
- slug_field='slug')
+
+ # relationships work this way:
+ # to add a new relationship, add a new key
+ # the value must be a tuple in which the first element is the view name (as specified in urls.py)
+ # and the second must be the lookup field, usually slug or id/pk
+ _relationships = {
+ 'layer': ('api_layer_detail', 'layer.slug'),
+ 'images': ('api_node_images', 'slug'),
+ }
class Meta:
model = Node
@@ -59,13 +63,10 @@ class Meta:
primary_fields += ['data']
secondary_fields = [
- 'access_level', 'layer', 'layer_name', 'added', 'updated',
- 'layer_details', 'images'
+ 'access_level', 'layer', 'layer_name',
+ 'added', 'updated', 'relationships'
]
- if PARTICIPATION_INSTALLED:
- secondary_fields += ['comments']
-
fields = primary_fields + secondary_fields
read_only_fields = ('added', 'updated')
2  nodeshot/core/nodes/tests.py
View
@@ -332,7 +332,7 @@ def test_node_details(self):
node = response.data
images_url = reverse('api_node_images', args=['fusolab'])
# images_url in node['images']
- self.assertIn(images_url, node['images'])
+ self.assertIn(images_url, node['relationships']['images'])
# PUT: 403 - must be logged in
response = self.client.put(url)
14 nodeshot/networking/net/models/__init__.py
View
@@ -18,6 +18,7 @@
from interfaces.vlan import Vlan
from interfaces.vap import Vap
+
__all__ = [
'RoutingProtocol',
'Device',
@@ -29,4 +30,15 @@
'Tunnel',
'Vlan',
'Vap'
-]
+]
+
+
+# ------ Add relationship to NodeDetailSerializer ------ #
+
+from nodeshot.core.nodes.serializers import NodeDetailSerializer
+
+NodeDetailSerializer.add_relationship(**{
+ 'name': 'devices',
+ 'view_name': 'api_node_devices',
+ 'lookup_field': 'slug'
+})
Please sign in to comment.
Something went wrong with that request. Please try again.