【问题标题】:Django REST foreign key issueDjango REST外键问题
【发布时间】:2019-11-26 14:57:07
【问题描述】:

尝试实现和测试我自己的序列化程序,我遇到了以下问题:

搜索了包括此错误消息在内的许多问题,但我没有找到任何解决问题的方法。

DRF 外键误用?

ValueError: Cannot assign "'effcad53-bc45-41fa-be43-4f22c0376eb5'": "Product.related_workspace" must be a "Workspace" instance.

工作区类:

class Workspace(models.Model):
    id = models.UUIDField(
            primary_key=True,
            default=uuid.uuid4,
    )
    related_login = models.ForeignKey(
            Login,
            on_delete=models.PROTECT,
    )
    description = models.CharField(
            max_length=150,
    )

    def __str__(self):
        login = Login.objects.get(pk=self.related_login_id)
        return f'{login.username} ({self.description})'

    class Meta:
        db_table = 'workspaces'

产品类:

class Product(models.Model):
    id = models.UUIDField(
            primary_key=True,
            default=uuid.uuid4,
    )
    related_workspace = models.ForeignKey(
            Workspace,
            on_delete=models.PROTECT,
    )
    code = models.CharField(
            max_length=50,
    )
    description = models.CharField(
            max_length=150,
    )

    class Meta:
        db_table = 'products'
        unique_together = ('related_workspace', 'code',)

ProductSerializer 类:

class ProductSerializer(serializers.Serializer):
    id = serializers.UUIDField(read_only=True)
    related_workspace = serializers.UUIDField()
    code = serializers.CharField()
    description = serializers.CharField()

    def create(self, validated_data):
        return Product.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.related_workspace = validated_data.get('related_workspace', instance.related_workspace)
        instance.code = validated_data.get('code', instance.code)
        instance.description = validated_data.get('description', instance.description)
        instance.save()
        return instance

我用来测试序列化程序的脚本:

PROJECT_NAME = 'api'


def main():
    #
    from api.applications.product.models import Product
    from api.applications.product.serializers import ProductSerializer
    #
    # Create a product
    #
    code = 'P001'
    description = f'Product {code}'
    #
    # This is a valid workspace id!
    #
    related_workspace = 'effcad53-bc45-41fa-be43-4f22c0376eb5'
    #
    product = Product(
            code=code,
            description=description,
            related_workspace=related_workspace,
    )
    product.save()
    #
    serializer = ProductSerializer(product)
    print('serializer.data:', serializer.data)


if __name__ == '__main__':
    import os

    os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % PROJECT_NAME)
    import django

    django.setup()
    main()

关于我缺少什么的任何建议?

【问题讨论】:

    标签: django-rest-framework


    【解决方案1】:

    首先,当您在 Django 中测试任何东西时,最简单的方法是在 test 模块中编写测试类并使用 manage.py 来运行它们。您正在执行的所有设置逻辑都已在 manage.py 中。

    python manage.py test my_app.tests.my_test_class

    在您的序列化程序中,您将外键设置为related_workspace = serializers.UUIDField(),而不是您想要嵌套您的序列化程序 (docs),以便提取工作区数据、序列化、保存并返回工作区对象。你应该有两个序列化程序,它们应该看起来像这样,我将使用ModelSerializer

    from rest_framework import serializers
    
    # Workspace Serializer
    class WorkspaceSerializer(serializers.ModelSerializer):
        class Meta:
            model = Workspace
            fields = "__all__"
    
    class ProductSerializer(serializers.ModelSerializer):
        related_workspace = WorkspaceSerializer()
    
        class Meta:
            model = Product
            fields = ["id", "related_workspace", "code", "description"]
    
        def create(self, validated_data):
            workspace_data = validated_data.pop('related_workspace')
    
            workspace_serializer = WorkspaceSerializer(data=workspace_data)
            if workspace_serializer.is_valid(reaise_exception=True):
                workspace = workspace_serializer.save()
                product = Product.objects.create(related_workspace = workspace, **validated_data)
                return product
    

    我们想要删除工作区数据,然后将其提供给它自己的序列化程序,如果该数据有效,我们保存序列化程序并获得一个 Workspace 对象作为回报。然后我们可以使用返回的工作区对象创建我们的 Product 对象。

    【讨论】:

    • 感谢您的快速回答,为我提供了有关此类测试的“DRFnic”建议。
    【解决方案2】:

    深入搜索,我的错误在于我创建 Product 实例的方式...

    在我的测试脚本中,我刚刚更新了:

        product = Product(
                code=code,
                description=description,
                related_workspace=related_workspace,
        )
    

    收件人:

        product = Product(
                code=code,
                description=description,
                related_workspace=Workspace.objects.get(pk=related_workspace)
        )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-15
      • 2019-07-02
      相关资源
      最近更新 更多