我可能没有添加太多内容,但在为没有表单的rest api编写单元测试时遇到了这个错误,因此我想提供一个示例来说明我是如何解决这个场景的。 我正在使用Django 4.1.7和Django Rest Framework 3.14.0。
这是一个Pokemon卡牌项目,因此有一个PokemonType模型(将类型表示为“火”,“水”,“草”等及其抗性和弱点):
class PokemonType(models.Model):
name = models.CharField(max_length=100, blank=False)
strong_vs = models.ManyToManyField('self', symmetrical=False, related_name="strong_versus")
weak_vs = models.ManyToManyField('self', symmetrical=False, related_name="weak_versus")
resistant_to = models.ManyToManyField('self', symmetrical=False, related_name="resists")
vulnerable_to = models.ManyToManyField('self', symmetrical=False, related_name="vulnerable")
我想编写一个简单的测试以验证能否创建PokemonType,但这个测试会导致“禁止向多对多集合的前向侧直接赋值”的错误:
class PokemonTypeModelTests(TestCase):
def test_create_pokemontype(self):
pokemon_type = PokemonType.objects.create(
name = 'type 1',
strong_vs = [],
weak_vs = [2],
resistant_to = [3, 4],
vulnerable_to = [2, 5]
)
pokemon_type_from_db = PokemonType.objects.get(id=pokemon_type.id)
self.assertEqual(pokemon_type_from_db.name, 'type 1')
有人可能认为创建对象,然后像这样添加关系可能会有所帮助:
pokemon_type = PokemonType.objects.create(name='type 1')
pokemon_type.resistant_to.set([3, 4])
但是这会引发错误django.db.utils.IntegrityError: 表 'api_pokemontype_resistant_to' 中主键为 '1' 的行具有无效的外键:api_pokemontype_resistant_to.to_pokemontype_id 包含一个值 '3',该值在 api_pokemontype.id 中没有相应的值。
这是因为具有id 3和4的PokemonType对象尚不存在(请记住Django为测试创建了一个特殊的数据库)。多对多关系实际上是作为数据库中的单独表实现的,Django需要对象实际存在于数据库中,然后才能在它们之间添加关系。
这就是为什么在这种情况下的解决方案是首先创建所有对象,将它们添加到数据库中,然后使用set()
来创建多对多关系:
def test_create_pokemontype(self):
pokemon_type = PokemonType.objects.create(name='type 1')
type2 = PokemonType.objects.create(name='type 2')
type3 = PokemonType.objects.create(name='type 3')
type4 = PokemonType.objects.create(name='type 4')
type5 = PokemonType.objects.create(name='type 5')
pokemon_type.strong_vs.set([])
pokemon_type.weak_vs.set([type2])
pokemon_type.resistant_to.set([type3, type4])
pokemon_type.vulnerable_to.set([type2, type5])
pokemon_type_from_db = PokemonType.objects.get(id=pokemon_type.id)
self.assertEqual(pokemon_type_from_db.name, 'type 1')
self.assertEqual(set(pokemon_type_from_db.strong_vs.all()), set())
self.assertEqual(set(pokemon_type_from_db.weak_vs.all()), {type2})
self.assertEqual(set(pokemon_type_from_db.resistant_to.all()), {type3, type4})
self.assertEqual(set(pokemon_type_from_db.vulnerable_to.all()), {type2, type5})
emails
中有多个电子邮件地址吗? - MD. Khairul Basar