You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django测试场景下如何正确配置ManyToManyField多对多关联

问题根因

你遇到的问题来自两个认知误区:

  • ManyRelatedManager.set() 方法本身无返回值,它的作用是直接修改数据库中的多对多关联关系,执行完成后不会返回关联对象的查询集,所以你将方法执行结果赋值给reader变量,拿到的必然是None,哪怕是没有自定义中间表的普通多对多字段也是如此。
  • 你的Book.readers字段指定了through='UserBookRelation'自定义中间表,这种场景下Django会禁用set()/add()/create()/remove()这类多对多快捷操作方法——因为自定义中间表通常会存在两个关联外键之外的其他必填字段,快捷方法无法为这些字段赋值,必须通过直接操作中间表的方式建立关联。
正确实现方式

测试用例中的关联配置

直接创建中间表实例即可建立多对多关联,需要获取关联用户列表时,单独调用all()方法查询:

from .models import Book, UserBookRelation

class BookSerializerTestCase(TestCase):

    def setUp(self):
        self.user = User.objects.create(username='test_username')
        self.book_1 = Book.objects.create(name='Test book 1', price=750, author_name='Author 1', owner=self.user)
        self.book_2 = Book.objects.create(name='Test book 2', price=650, author_name='Author 1', owner=self.user)

    def test_readers(self):
        # 直接创建中间表记录建立关联,如果中间表有其他必填字段要一并传入
        UserBookRelation.objects.create(book=self.book_1, user=self.user)
        # 主动查询关联的读者列表
        readers = self.book_1.readers.all()
        print(f'Readers: {readers}')
        # 可以加断言校验关联是否生效
        self.assertEqual(readers.count(), 1)
        self.assertEqual(readers.first(), self.user)

序列化器create方法适配

如果要在序列化器创建Book实例时自动处理readers关联,需要重写序列化器的create方法,在保存Book实例后手动创建中间表记录,示例:

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

    def create(self, validated_data):
        readers_data = validated_data.pop('readers', [])
        book = Book.objects.create(**validated_data)
        # 批量创建中间表关联
        for user in readers_data:
            UserBookRelation.objects.create(book=book, user=user)
        return book
注意事项

如果你的UserBookRelation中间表存在除book、user外的其他非空字段(比如评分、是否点赞、阅读进度等),创建中间表记录时必须传入对应字段的值,否则会触发数据库非空约束报错。

内容的提问来源于stack exchange,提问作者Mikhail Tochenov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 02:54:20