Внешний ключ в сериализаторе читается как HyperlikedModelSerializer, но записывается только с идентификатором

У меня есть модель Django, в которой в качестве внешнего ключа есть поле, связанное с пользователем.

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

Я хочу, чтобы мой сериализатор показывал как идентификатор, так и имя пользователя для этой модели, поэтому это выглядит так:

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

Но когда я добавляю новое уведомление, я хочу отправить только идентификатор пользователя, например:

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

Я попытался использовать гиперссылку в своем сериализаторе:

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')

Но происходит то, что таким образом мне нужно отправить как идентификатор, так и имя пользователя при публикации нового уведомления.

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

Как я могу решить эту проблему, чтобы я мог создать уведомление только с идентификатором пользователя, но получить как идентификатор, так и имя, читая список уведомлений?


person t.pimentel    schedule 21.05.2015    source источник


Ответы (1)


Я взламываю эту проблему, одновременно отправляя и id, и obj, но делая obj доступным только для чтения:

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')
    #                    ^^^^^^    ^^^^^^^^^^

Таким образом, у вас есть доступ к идентификатору отправителя и вы можете писать ему, но у вас также есть доступ к самому объекту отправителя. Вам придется вручную синхронизировать их на стороне клиента. В соответствии с required=False вам не нужно отправлять объект-отправитель при публикации результатов, и, поскольку это также read_only, все обновления этого объекта будут игнорироваться сервером.

Вы также можете сделать поле sender доступным только для записи, чтобы оно не отправлялось с сервера:

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

Я все еще использую DRF 2.4.4, поэтому вам, возможно, придется настроить приведенный выше синтаксис для DRF 3.+.

person Ross Rogers    schedule 21.05.2015