Django:如何在 Factory Boy 工厂和序列化器中正确使用 ManyToManyField?

gps*_*ugy 5 django manytomanyfield django-serializer factory-boy

问题

我正在使用一个模型类Event,其中包含另一个模型类的可选UserManyToManyField (不同的事件可以有不同的用户),以及一个带有序列化器的工厂类EventFactory(使用 Factory Boy 库)EventSerializer。我相信我已按照文档进行工厂制作和序列化,但收到错误:

ValueError:“<事件:测试事件>”需要有字段“id”的值,然后才能使用此多对多关系。

我知道在链接它们之前必须在 ManyToMany 中创建两个模型实例,但我看不到添加发生在哪里!

问题

有人可以澄清如何以我尚未采用的方式使用模型、工厂男孩和序列化器来正确使用 ManyToManyField 吗?

设置

这是我的代码:

模型.py

@python_2_unicode_compatible
class Event(CommonInfoModel):
    users = models.ManyToManyField(User, blank=True, related_name='events')
    # other basic fields...
Run Code Online (Sandbox Code Playgroud)

工厂.py

class EventFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Event

    @factory.post_generation
    def users(self, create, extracted, **kwargs):
        if not create:
            # Simple build, do nothing.
            return

        if extracted:
            # A list of users were passed in, use them
            # NOTE: This does not seem to be the problem. Setting a breakpoint                     
            # here, this part never even fires
            for users in extracted:
                self.users.add(users)
Run Code Online (Sandbox Code Playgroud)

序列化器.py

class EventSerializer(BaseModelSerializer):
    serialization_title = "Event"
    # UserSerializer is a very basic serializer, with no nested 
    # serializers
    users = UserSerializer(required=False, many=True)

    class Meta:
        model = Event
        exclude = ('id',)
Run Code Online (Sandbox Code Playgroud)

测试.py

class EventTest(APITestCase):
@classmethod
def setUpTestData(cls):
    cls.user = User.objects.create_user(email='test@gmail.com',  
    password='password')

def test_post_create_event(self):
    factory = factories.EventFactory.build()
    serializer = serializers.EventSerializer(factory)

    # IMPORTANT: Calling 'serializer.data' is the exact place the error occurs!
    # This error does not occur when I remove the ManyToManyField
    res = self.post_api_call('/event/', serializer.data)
Run Code Online (Sandbox Code Playgroud)

版本信息

  • 姜戈 1.11
  • Python 2.7.10

感谢您提供的任何帮助!

mal*_*rts 2

关于错误:似乎缺少id是由于使用了.build()而不是.create()(或只是EventFactory())。前者不保存模型,因此它不会获取值id,而后者则获取值(请参阅工厂文档模型文档)。

我怀疑序列化程序仍然期望对象具有id,即使多对多关系是可选的,因为它无法在没有id.

但是,对于实际任务可能有更简单的解决方案。上述方法是生成传递给 的 POST 数据的一种方式post_api_call()。如果这些数据是手动创建的,那么工厂和序列化器就变得不必要了。从测试的角度来看,显式数据方法甚至可能更好,因为您现在可以看到必须产生预期结果的确切数据。而对于工厂和序列化器方法,它在测试中实际使用的内容中更加隐含。