首页 文章

如何在Django REST Framework中序列化继承的模型

提问于
浏览
2

我正在开发一个Django Rest Framework项目,我在其中创建了以下模型:

from django.db import models

# Base Models...
choices = (
    ('Single', 'Single'),
    ('Multiple', 'Multiple'),
)


class UserAccountModel(models.Model):
    deployment_name = models.CharField(max_length=150, blank=True)
    credentials = models.FileField(upload_to='media/credentials/', name='credentials'),
    project_name = models.CharField(max_length=150, blank=True)
    project_id = models.CharField(max_length=100, blank=False, name='project_id')
    cluster_name = models.CharField(max_length=150, blank=False)
    zone_region = models.CharField(max_length=150, blank=False)
    services = models.CharField(max_length=100, choices=choices)

    def __str__(self):
        return self.deployment_name


class AwdModel(UserAccountModel):
    source_zip = models.FileField(upload_to='media/awdSource/', name='awd_source')
    routing = models.TextField(name='routing', null=True)

    def __str__(self):
        return self.deployment_name

    def save(self, **kwargs):
        if not self.id and self.services == 'Multiple' and not self.routing:
            raise ValidationError("You must have to provide routing for multiple services deployment.")
        super().save(**kwargs)

    # def clean(self):
    #     if self.services == 'Multiple' and self.routing is None:
    #         raise ValidationError('You must have to provide routing for multiple services deployment.')


class AwodModel(UserAccountModel):
    source_zip = models.FileField(upload_to='media/awodSource/', name='awod_source')
    routing = models.TextField({'type': 'textarea'}, name='routing')

    def save(self, **kwargs):
        if not self.id and self.services == 'Multiple' and not self.routing:
            raise ValidationError("You must have to provide routing for multiple services deployment.")
        super().save(**kwargs)

我需要序列化这些模型,以下是我为这些模型实现的序列化器:

from rest_framework import serializers
from .models import UserAccountModel, AwdModel, AwodModel


class UserAccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserAccountModel
        fields = ('deployment_name', 'credentials', 'project_name',
                  'project_id', 'cluster_name', 'zone_region', 'services')


class AWDSerializer(serializers.ModelSerializer):
    class Meta(UserAccountSerializer.Meta):
        model = AwdModel
        fields = UserAccountSerializer.Meta.fields + ('awd_source', 'routing',)


class AWODSerializer(serializers.ModelSerializer):
    class Meta:
        model = AwodModel
        fields = '__all__'

但是,当我尝试访问时,AWDSerialzer会返回错误:

尝试在序列化程序AWDSerializer上获取字段project_id的值时,/ api / v1 / deployments / Got AttributeError中的AttributeError . 序列化程序字段可能名称不正确,并且与QuerySet实例上的任何属性或键都不匹配 . 原始异常文本是:'QuerySet'对象没有属性'project_id' .

Update: Here's my APIView code:

class DeploymentsList(APIView):
    def get(self, request):
        MAX_OBJECTS = int(20)
        deployments = AwdModel.objects.all()[:MAX_OBJECTS]
        data = AWDSerializer(deployments).data
        return Response(data)


class DeploymentDetail(APIView):
    def get(self, request, *args, **kwargs):
        deployment = get_object_or_404(AwdModel, pk=kwargs['pk'])
        data = AWDSerializer(deployment).data
        return Response(data)

请帮帮我!

提前致谢!

3 回答

  • 0

    尝试在序列化程序AWDSerializer上获取字段project_id的值时,/ api / v1 / deployments / Got AttributeError中的AttributeError . 序列化程序字段可能名称不正确,并且与QuerySet实例上的任何属性或键都不匹配 . 原始异常文本是:'QuerySet'对象没有属性'project_id' .

    尝试从字段 project_id 获取值时,这是属性错误 .

    摆脱 project_id 字段中的 name 属性 .

    Edit The APIView code

    要序列化查询集或对象列表而不是单个对象实例,应在实例化序列化程序时传递many = True标志 . 然后,您可以传递要序列化的查询集或对象列表 . [序列化多个对象]

    class DeploymentsList(APIView):
        def get(self, request):
            MAX_OBJECTS = int(20)
            deployments = AwdModel.objects.all()[:MAX_OBJECTS]
            data = AWDSerializer(deployments, many=True).data
            return Response(data)
    

    我希望这将有所帮助 .

  • 1

    您发布的代码似乎有效且正确 . 然而,这个问题是无关紧要的 . 异常文本 'QuerySet' object has no attribute 'project_id' 指的是可能源自QuerySet中的restframework app 's views.py file. The exception states that you are attempting to access the attribute ' project_id'的问题 .

    QuerySet是(延迟加载的)模型集,而不是单个模型 . 即使查询集只有一个元素,在访问该元素之前仍然需要访问该元素 .

    因为你确定 here is an incorrect use case exampleMyModel.objects.all().project_id 无法确定问题所在 . 在这里,我们可以看到我试图从查询集中访问属性 project_id . 一个正确的用例是 MyModel.objects.all()[0].project_id . 但是,这假定查询集不为空 .

    实际上,大多数DjangoRestFramework视图都继承自 rest_framework.views.APIView ,它继承了django的View Class . 我建议检查该类中的 query_set 是否正确使用 .

    欢迎在此分享您的实施,以获得进一步的评论 .

    [EDIT] - After views.py coded was added.

    您正在尝试使用序列化程序 data = AWDSerializer(deployments).data 的实例化序列化整个查询集,这会导致属性错误 .

    我建议使用 generics.ListAPIView 类并使用类属性 query_setserializer_class . 这些很容易实现 . 然后,您可以调用APIViews默认的get方法 . 以下是 DeploymentsList view 的示例

    from rest_framework import generics
    
    class DeploymentsList(generics.ListAPIView):
        serializer_class = AWDSerializer
        queryset = AwdModel.objects.all()
    
        def get(self, request, *args, **kwargs):
            MAX_OBJECTS = int(20)
            self.queryset = self.queryset[:MAX_OBJECTS]
            return super(DeploymentsList, self).get(request, *args, **kwargs)
    

    [EDIT] - FileField Serialization 为了序列化UserAccount.credentials文件字段以便我们序列化路径,我们可以使用 serializers.SerializerMethodField . 即您的UserAccountSerializer变为:

    class UserAccountSerializer(serializers.ModelSerializer):
        credentials = serializers.SerializerMethodField()
    
        def get_credentials(self, user_account):
            return user_account.credentials.path
    
        class Meta:
            model = UserAccountModel
            fields = ('deployment_name', 'credentials', 'project_name',
                      'project_id', 'cluster_name', 'zone_region', 'services')
    
  • 1

    当你从一个未在其自己的元类中定义为abstract的模型类继承时,Django会在子类及其父类之间创建一对一的关系 . 这实际上在数据库中创建了两个表;一个用于基类,一个用于子类 .


    我没有尝试过您的代码,也没有使用过Django 2,但会检查两个序列化程序之间的关系字段 .

相关问题