5

Im using stream-django with django REST framework and the enriched activities are throwing "not JSON serializable" on the objects returned from enrichment, which is as expected as they have not gone through any serializing.

How do i customize the enrichment process so that it returns a serialized object from my drf serializer and not the object itself?

Some example data, not enriched:

"is_seen": false,
"is_read": false,
"group": "19931_2016-04-04",
"created_at": "2016-04-04T08:53:42.601",
"updated_at": "2016-04-04T11:33:26.140",
"id": "0bc8c85a-fa59-11e5-8080-800005683205",
"verb": "message",
"activities": [
    {
    "origin": null,
    "verb": "message",
    "time": "2016-04-04T11:33:26.140",
    "id": "0bc8c85a-fa59-11e5-8080-800005683205",
    "foreign_id": "chat.Message:6",
    "target": null,
    "to": [
    "notification:1"
    ],
"actor": "auth.User:1",
"object": "chat.Message:6"
}

The view:

def get(self, request, format=None):
    user = request.user
    enricher = Enrich()
    feed = feed_manager.get_notification_feed(user.id)
    notifications = feed.get(limit=5)['results']
    enriched_activities=enricher.enrich_aggregated_activities(notifications)
    return Response(enriched_activities)
Ruben Schmidt
  • 141
  • 1
  • 6
  • How did you configure stream-django? I am facing a hard time configuring it. Could you please help me? – Rohan May 05 '18 at 22:09

2 Answers2

3

I solved it by doing the following:

property tag on the model that returns the serializer class

@property
def activity_object_serializer_class(self):
    from .serializers import FooSerializer
    return FooSerializer

Then used this to serialize the enriched activities. Supports nesting.

@staticmethod
def get_serialized_object_or_str(obj):
    if hasattr(obj, 'activity_object_serializer_class'):
        obj = obj.activity_object_serializer_class(obj).data
    else:
        obj = str(obj)  # Could also raise exception here
    return obj

def serialize_activities(self, activities):
    for activity in activities:
        for a in activity['activities']:
            a['object'] = self.get_serialized_object_or_str(a['object'])
            # The actor is always a auth.User in our case
            a['actor'] = UserSerializer(a['actor']).data
    return activities

and the view:

def get(self, request, format=None):
    user = request.user
    enricher = Enrich()
    feed = feed_manager.get_notification_feed(user.id)
    notifications = feed.get(limit=5)['results']
    enriched_activities = enricher.enrich_aggregated_activities(notifications)
    serialized_activities = self.serialize_activities(enriched_activities)
    return Response(serialized_activities)
Ruben Schmidt
  • 141
  • 1
  • 6
  • could you share more about your serializer? I tried adding `get_serialized_object_or_str` and `serialize_activities` to my view and got the error `HyperlinkedIdentityField requires the request in the serializer context. Add context={'request': request} when instantiating the serializer.` – Harry Moreno Jun 03 '19 at 23:00
  • @HarryMoreno I am sorry, i can't remember the implementation and i do not have access to that source code anymore. This is question is quite old and i'm sure there are better ways to solve this today! – Ruben Schmidt Jun 06 '19 at 06:54
  • You'd be surprised. I think I'm one of the few people that is working towards documenting a solution for drf and getstream :p – Harry Moreno Jun 06 '19 at 16:22
0

The enrich step replaces string references into full Django model instances.

For example: the string "chat.Message:6" is replaced with an instance of chat.models.Message (same as Message.objects.get(pk=6)).

By default DRF does not know how to serialize Django models and fails with a serialization error. Luckily serializing models is a very simple task when using DRF. There is a built-in serializer class that is specific to Django models (serializers.ModelSerializer).

The documentation of DRF explains this process in detail here: http://www.django-rest-framework.org/api-guide/serializers/#modelserializer.

In your case you probably need to use nested serialization and make the serialization of the object field smart (that field can contain references to different kind of objects).

There is an open issue about this on Github: https://github.com/GetStream/stream-django/issues/38. Ideally this is something the library will provide as helper/example, so any code contribution / input will help making that happen.

Tommaso Barbugli
  • 11,781
  • 2
  • 42
  • 41