1

I have a Django model which has, as a foreign key, a field related to a User.

class Notification(models.Model):
    sender = models.ForeignKey(User, null=True)
    is_read = models.BooleanField(default=False)

I want my serializer to show both the id and name of the user for this model so it's like this:

{
    "count": 45,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2,
            "sender": {
                "id": 2,
                "name": "my_name",
            }
            "is_read": false,
        }
    ]
}

But when I add a new notification I want to send only the user's id, like this:

$ curl -X POST http://127.0.0.1:8000/notifications/ -H "Content-Type: application/json" -d "{\"sender\":\"4\"}"

I tried using a hyperlink in my serializer:

class NotificationSenderSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'name')

class NotificationSerializer(serializers.ModelSerializer):
    sender_name = serializers.NotificationSenderSerializer()

    class Meta:
        model = Notification
        fields = ('id', 'sender', 'is_read')

But what happens is that, this way, I need to send both the id and the name of the user when posting a new notification.

$ curl -X POST http://127.0.0.1:8000/notifications/ -H "Content-Type: application/json" -d "{\"sender\": {\"id\": \"4\", \"name\":\"my_name\"} }"

How can I solve this problem so that I can create a notification with only the user id, but receive both the id and name back reading the list of notifications?

Kevin Brown-Silva
  • 40,873
  • 40
  • 203
  • 237
t.pimentel
  • 1,465
  • 3
  • 17
  • 24

1 Answers1

1

I hack around this very issue by sending both the id and the obj at the same time, but making the obj read-only:

class NotificationSerializer(serializers.ModelSerializer):
    sender_obj = serializers.NotificationSenderSerializer(
        source="sender", read_only=True, required=False)
    #                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    class Meta:
        model = Notification
        fields = ('id', 'sender', 'sender_obj', 'is_read')
    #                    ^^^^^^    ^^^^^^^^^^

This way, you have access to the sender id and can write to it, but you also have access to the sender object itself. You will have to manually keep these in sync' on the client side. In accordance with required=False, you don't have to send the sender object when you post the results and since it is also read_only all updates to that object will be ignored by the server.

You could also make the sender field write-only, so it isn't sent from the server:

sender = serializers.IntegerField(
    required=False,
    write_only=True, # <---
    allow_none=True,
    blank=True)

I'm still using DRF 2.4.4, so you may have to tweak the above syntax for DRF 3.+

Ross Rogers
  • 23,523
  • 27
  • 108
  • 164