嵌套序列化程序中的不完整媒体 url

Incomplete media url in nested serializers

我有一个 django-rest-api 应用程序,其中包含模型 Record、Tag 和 Weight,其中 Record 和 Tag 通过权重模型具有多对多关系:

# models.py
class Tag(models.Model):
    image = models.ImageField(upload_to='tag_images', null=True, blank=True)

class Record(models.Model):
    file = models.FileField(upload_to='record_files', null=True, blank=True)

class Weight(models.Model):
    record = models.ForeignKey(
        Record,
        related_name='weights',
        on_delete=models.CASCADE
    )
    tag = models.ForeignKey(
        Tag,
        related_name='weights',
        on_delete=models.CASCADE
    )
    value = models.IntegerField()

    class Meta:
        unique_together = ('record', 'tag',)

记录和标记模型都有一个 FileField/ImageField 参数。在我的 REST API 视图中,我想显示记录详细信息及其完整文件 url 和所有相关标签及其完整图像 url。这就是我的序列化器的样子:

# serializers.py
class RecordSerializer(serializers.ModelSerializer):
    tags = serializers.SerializerMethodField()

    class Meta:
        model = Record
        fields = ('id', 'file', 'tags')

    def get_tags(self, obj):
        return TagSerializer(Tag.objects.filter(weights__in=obj.weights.all()), many=True).data

class TagSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tag
        fields = ('id', 'image')

问题是,当我看到记录详细信息时,它的文件 url 是完整的,但标签图像 url 不是:

# record detail results
{
    "id": 1,
    "file": "http://127.0.0.1:8080/media/record_files/record00.mp3",
    "tags": [
        {
            "id": 4,
            "image": "/media/tag_images/image04.jpg"
        },
        {
            "id": 10,
            "image": "/media/tag_images/image10.jpg"
        }
    ]
}

最后,我通过创建一个单独的标签列表视图绕过了这个问题,现在 url 已经完成,尽管我的 serializers.py.

# record tag list results
[
    {
        "id": 4,
        "image": "http://127.0.0.1:8080/media/tag_images/image04.jpg"
    },
    {
        "id": 10,
        "image": "http://127.0.0.1:8080/media/tag_images/image10.jpg"
    }
]

我想这是一个更干净的 rest api 解决方案(尽管我很确定我不需要单独记录详细信息及其标签)。尽管如此,当数据是嵌套序列化程序的一部分时,为什么 url 不完整仍然让我感到困惑。这是它的本意还是我做错了什么?

看起来您可能找到了更好的解决方案,但以防万一您仍然好奇:您最初尝试的问题是您将 "nested" 序列化程序调用放在 SerializerMethodField 中。声明 nested serializer 的通常方法是在设置实际字段时初始化序列化程序。在您的情况下,它看起来像这样:

class RecordSerializer(serializers.ModelSerializer):
    tags = TagSerializer()

当您这样做时,TagSerializer 可以从父序列化程序推断上下文,并且该上下文的一部分是请求。然后在 to_representation 调用 build_absolute_uri 中使用它来生成您希望的完整 url。

在您的视图中像这样初始化您的序列化程序:

serialized_store = StoreSerializer(store, context={"request": request})

source

您需要覆盖方法:

def get_serializer_context(self):
        return {'request': self.request}