【问题标题】:How to access/create a proper Request object for DRF Serializer?如何为 DRF 序列化器访问/创建正确的请求对象?
【发布时间】:2017-08-20 15:46:28
【问题描述】:

我使用 DRF 创建了一个 REST API,它运行良好。前端是一个简单的页面,允许查看和更新​​数据。现在我正在尝试使用带有django-channels 的WebSockets 向站点添加更多交互性。 Channels 系统使用起来相当简单,而且运行良好。

但是,我现在面临的问题是尝试将所有移动部件组合在一起以协同工作。我的想法是,初始页面刷新来自 REST API,任何后续更新都会在每次更新后自动通过 WebSocket 进行(借助post_save 信号)。我的所有模型都有很好的 DRF 序列化器,但遗憾的是,如果没有 Request 对象(例如 HyperLinkedIdentityField),它们就无法工作:

AssertionError: `HyperlinkedIdentityField` requires the request in the serializer context. Add `context={'request': request}` when instantiating the serializer.

所以我的问题是,当尝试在信号处理程序中序列化我的模型时,如何以某种方式创建/伪造序列化程序想要的正确请求对象?

编辑

我对此想得越多,就越明显地发现这不是正确的方法。无法为序列化程序制作单个通用的 Request 对象,因为触发它们的模型更新可以来自任何来源。因此,即使尝试创建一个也是没有意义的。我想我必须分离“基本”序列化程序(没有任何超链接)并使用它们向客户端发送更新。由于超链接永远不会改变,我认为这是正确的方法。

【问题讨论】:

  • 我不明白“我如何以某种方式创建序列化程序想要的请求对象?”
  • 请求对象来自您的视图参数。基本上你可以像这样创建序列化程序实例:Serializer_class(instance, data=data, context={"request": request})
  • 在正常情况下确实有效,但由于这是在信号处理程序 (@receive(post_save, sender=MyModel)) 内部,因此既没有查看也没有请求使用。

标签: django django-rest-framework django-channels


【解决方案1】:

如果有人可能感兴趣,这就是我解决问题的方法。主要的代码片段如下。

首先是一个简单的模型(myapp/models.py):

from django.db import models

class MyModel(models.Model):
    name = models.TextField()

然后是序列化程序(myapp/serializers.py):

from rest_framework import serializers

MyModelSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = MyModel
        fields = ('url', 'id', 'name')
        extra_kwargs = {'url': {'view_name': 'mymodel-detail'}}

MyModelBaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = ('id', 'name')

以及视图(myapp/views.py):

from rest_framework import viewsets
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer

class MyModelViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

最后是 Channels 消息消费者 (myapp/consumers.py):

import json
from django.db.models.signals import pre_save
from django.dispatch import receiver
from channels import Group
from myapp.models import MyModel
from myapp.serializers import MyModelBaseSerializer

def ws_add(message):
    message.reply_channel.send({"accept": True})
    Group("mymodel").add(message.reply_channel)

def ws_disconnect(message):
    Group("mymodel").discard(message.reply_channel)

@receiver(post_save, sender=MyModel)
def mymodel_handler(sender, instance, **kwargs):
    Group("mymodel").send({
        "text": json.dumps({
            "model": "mymodel",
            "data": MyModelBaseSerializer(instance).data
        })
    })

我省略了 urls.py 和 routing.py 之类的内容,但这些内容与问题无关。可以看出,常规视图使用包含 URL 的普通 MyModelSerializer,然后更新处理程序 MyModelBaseSerializer 只有不依赖于任何 Request 对象的字段。

【讨论】:

猜你喜欢
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多