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

基于多对多关系Django模型,如何在单元测试中表示外键查找表?

Django单元测试中外键查找表(ListType)的处理方法

我来给你捋捋怎么在Django单元测试里处理这个list_type外键查找表哈~ 其实核心思路就是先预创建测试用的查找表实例,然后在后续的测试用例里直接复用这些实例来关联其他模型,下面给你一步步拆解:

第一步:先明确你的模型结构(参考)

首先得确保你的模型定义是正确的,这里先给出符合你需求的模型示例,方便后续测试代码对应:

from django.db import models
from django.contrib.auth.models import User

# 外键查找表:活动类型
class ListType(models.Model):
    name = models.CharField(max_length=50, unique=True)  # 类型名称唯一

    def __str__(self):
        return self.name

# 活动项目模型
class Item(models.Model):
    name = models.CharField(max_length=100)
    type = models.ForeignKey(ListType, on_delete=models.CASCADE, related_name='items')
    # 可添加其他字段:event_date(活动日期)、location(地点)等

# 用户的项目列表模型
class UserList(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')
    name = models.CharField(max_length=50)
    items = models.ManyToManyField(Item, related_name='lists')  # 多对多关系

第二步:在测试类中预创建ListType实例

推荐在测试类的setUp方法里创建测试用的活动类型,这样每个测试方法都能直接复用,避免重复代码:

from django.test import TestCase
from django.contrib.auth.models import User
from .models import ListType, Item, UserList

class ListAndItemTests(TestCase):
    def setUp(self):
        # 批量创建测试用的活动类型
        self.movie_type = ListType.objects.create(name='电影')
        self.concert_type = ListType.objects.create(name='音乐会')
        self.sport_type = ListType.objects.create(name='体育赛事')
        
        # 顺便创建测试用户,方便测试用户列表
        self.test_user = User.objects.create_user(username='jim', password='test123456')

第三步:编写具体的测试用例

接下来就可以基于预创建的ListType实例,测试各种关联场景了:

测试1:验证活动项目与ListType的外键关联正确

def test_item_has_correct_list_type(self):
    # 创建一个关联「电影」类型的项目
    movie_item = Item.objects.create(name='流浪地球2', type=self.movie_type)
    
    # 验证外键指向正确
    self.assertEqual(movie_item.type, self.movie_type)
    self.assertEqual(movie_item.type.name, '电影')
    
    # 验证反向关联:ListType能找到对应的项目
    self.assertIn(movie_item, self.movie_type.items.all())

测试2:验证用户列表与多类型项目的关联

def test_user_list_contains_multiple_item_types(self):
    # 创建不同类型的活动项目
    movie_item = Item.objects.create(name='满江红', type=self.movie_type)
    concert_item = Item.objects.create(name='五月天演唱会', type=self.concert_type)
    sport_item = Item.objects.create(name='NBA总决赛', type=self.sport_type)
    
    # 创建用户列表并添加项目
    my_list = UserList.objects.create(user=self.test_user, name='我的必体验清单')
    my_list.items.add(movie_item, concert_item, sport_item)
    
    # 验证列表中项目数量正确
    self.assertEqual(my_list.items.count(), 3)
    
    # 验证各类型项目的数量符合预期
    self.assertEqual(my_list.items.filter(type=self.movie_type).count(), 1)
    self.assertEqual(my_list.items.filter(type=self.concert_type).count(), 1)

测试3:验证ListType的唯一约束

因为我们给name字段加了unique=True,所以要测试重复创建同名类型会报错:

def test_list_type_name_unique(self):
    # 尝试创建同名的「电影」类型,应该抛出异常
    with self.assertRaises(Exception):
        ListType.objects.create(name='电影')

小技巧

  • 如果需要创建大量测试用的ListType,可以用bulk_create提高效率:
    ListType.objects.bulk_create([
        ListType(name='电影'),
        ListType(name='音乐会'),
        ListType(name='体育赛事'),
        ListType(name='展览')
    ])
    
  • 如果你有固定的测试数据,也可以用Django的fixture来加载,不过setUp方法更灵活,适合动态调整测试数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:54:38