【问题标题】:DRF: Full Example of ListSerializer like Django's Admin-Inline?DRF:ListSerializer 的完整示例,如 Django 的 Admin-Inline?
【发布时间】:2022-02-06 22:19:16
【问题描述】:

我正在尝试将 DRF 的 ListSerializer 与外键模型结合起来。目的是拥有类似于 Django 的 admin-inline Formula 的东西。不幸的是,我在文档或 SO 示例中找不到完整示例:两个模型、两个序列化程序和一个视图集。

假设我们有一个类似 SO 示例 DRF ListSerializer and ListField 的模型:

class Musician(models.Model):

    name = models.CharField(max_length=50)
    comment = models.TextField(blank=True)

class Album(models.Model):
    artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)

所以我尝试将它们放入这样的序列化程序中:

class AlbumSerializer(serializers.ModelSerializer):

    class Meta:
        fields = 'artist', 'title'
        model = Album

class MusicianSerializer(serializers.ModelSerializer):

    class Meta:
        fields = 'name', 'comment', 'albums'
        model = Musician

    albums = serializers.ListSerializer(child=AlbumSerializer(), source='album_set')

然后我想在其上构建一个 ModelViewSet,以便我可以使用它,就像在 Django-Admin-Inline 中一样。但这不是那样工作的:

class MusicianViewSet(viewsets.ModelViewSet):

    queryset = Musician.objects.all()
    serializer_class = MusicianSerializer

但是很难测试,HTML 前端确实可以工作,并且在测试中我(在稍微不同的情况下)收到类似以下的错误消息:

{'album_set': [ErrorDetail(string='This field is required.', code='required')]}

我无法理解,即使在源代码中挖掘了几个小时之后。 那么我错过了什么?理想情况下,什么是 POST、PUT 和 DESTROY 的完整工作示例,在子模型对象上创建修改或删除?

[编辑:我正在使用 Django==4.0.1 和 django-extensions==3.1.5]

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    你可以在你的模型中使用related_name

    class Album(models.Model):
        artist = models.ForeignKey(Musician, on_delete=models.CASCADE, related_name='albums')
        name = models.CharField(max_length=100)
    

    然后在你的序列化器中调用它

    class MusicianSerializer(serializers.ModelSerializer):
        albums = AlbumSerializer(many=True, read_only=True)
        class Meta:
            fields = ['name', 'comment', 'albums']
            model = Musician
    

    【讨论】:

    • 好吧,恕我直言,这还不够。 "albums" 甚至不会出现在 HTML API 中。并且尝试在 Raw data 中直接填写 JSON 会给我很多奇怪的错误消息。
    • 好的,没有“奇怪的错误信息”(我的错误)。但在当前状态下,它只是忽略了发送的 JSON 的"albums" 数据。
    【解决方案2】:

    好的,所以有不同的错误,这里有一些解决问题的提示。 首先在序列化器中有两个错误,我们不能序列化父artist,我们要在Musician序列化器中添加一个create方法:

    class AlbumSerializer(serializers.ModelSerializer):
    
        class Meta:
            fields = 'title',
            model = Album
    
    
    class MusicianSerializer(serializers.ModelSerializer):
    
        class Meta:
            fields = 'id', 'name', 'comment', 'albums',
            model = Musician
    
        albums = AlbumSerializer(many=True)
    
        def create(self, validated_data):
            album_data = validated_data.pop('albums')
            muse = Musician.objects.create(**validated_data)
            for alb in album_data:
                muse.albums.create(**alb)
            return muse
    

    这可以直接在测试中进行测试,这里有一些关于关系序列化和间接编写关于序列化器的测试的提示: https://www.django-rest-framework.org/api-guide/relations/.

    有了这个,我可以通过runscript django-extension 命令运行django 脚本,包括rest_framework.test.RequestsClientrequests.Session(在后一种情况下,我们将使用runserver 命令启动服务器)。

    脚本可能如下所示:

    def run():
        client = requests.Session()
        client.auth = requests.auth.HTTPBasicAuth(username, password)
    
       TEST_DATA = {
           "name": "Miles Davis",
           "comment": "Great Stuff",
           "albums": [{"title": "B.B."}, {"title": "Don't know"}],
        }
        response = client.post(create_music_url, json=TEST_DATA)
    

    我发现这有助于理解代码是正确的,而测试是错误的,但我仍然无法开始工作......

    [编辑] 以下是使用rest_framework.test.APITestCase 及其self.clientforce_authenticate 的测试中的错误消息:

       response = self.client.post(music_url, json=TEST_DATA)
    

    response.data 如下: {'name': [ErrorDetail(string='This field is required.', code='required')], 'albums': [ErrorDetail(string='This field is required.', code='required')]}

       response = self.client.post(music_url, TEST_DATA)
    

    我明白了 {'albums': [ErrorDetail(string='This field is required.', code='required')]}

    恕我直言,这些错误消息至少可以说令人困惑......

    【讨论】:

    • 我终于明白了,我需要将format="json" 添加到我的client.post 呼叫中。呃...
    猜你喜欢
    • 1970-01-01
    • 2014-03-13
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 2017-11-24
    • 1970-01-01
    相关资源
    最近更新 更多