Как сериализовать унаследованные модели в Django REST Framework - PullRequest
0 голосов
/ 25 июня 2018

Я работаю над проектом 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 возвращает ошибку как:

AttributeError в / api / v1 / deployments / Got AttributeError при попытке получить значениедля поля project_id на сериализаторе AWDSerializer.Поле сериализатора может иметь неправильное имя и не соответствовать ни одному атрибуту или ключу в экземпляре QuerySet.Исходный текст исключения был: у объекта 'QuerySet' нет атрибута 'project_id'.

Обновление: вот мой код APIView:

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 голосов
/ 25 июня 2018

AttributeError в / api / v1 / deployments / Got AttributeError, когда Попытка получить значение для поля project_id на сериализаторе AWDSerializer. Поле сериализатора может быть названо неправильно и не сопоставить любой атрибут или ключ в экземпляре QuerySet. оригинал текст исключения был: объект 'QuerySet' не имеет атрибута 'project_id'.

Это ошибка атрибута при попытке получить значение из поля project_id.

Избавьтесь от атрибута name в поле project_id.

Редактировать код APIView

Чтобы сериализовать набор запросов или список объектов вместо одного объекта Например, вы должны передать флаг 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)

Надеюсь, это поможет.

0 голосов
/ 25 июня 2018

Когда вы наследуете от класса модели, который не определен как abstract в его собственном метаклассе, тогда Django создает отношение один-к-одному между подклассом и его родителем. Который на самом деле создает две таблицы в базе данных; один для базового класса и один для подкласса.


Я не пробовал ваш код и не использовал Django 2, но проверил бы, используя реляционное поле между двумя сериализаторами.

0 голосов
/ 25 июня 2018

Код, который вы разместили, кажется действительным и правильным.Проблема, однако, не связана.Текст исключения 'QuerySet' object has no attribute 'project_id' Относится к проблеме, которая, вероятно, возникла из файла views.py приложения restframework.Исключение говорит о том, что вы пытаетесь получить доступ к атрибуту project_id из QuerySet.

QuerySet - это (загруженный ленивый) набор моделей, а не одна модель.Даже если в наборе запросов был только один элемент, вам все равно потребуется доступ к этому элементу до доступа к его атрибутам.

Поскольку вы не предоставили доступ к файлу views.py, я не могу точно сказать, гдепроблема, однако, , вот неправильный пример использования : MyModel.objects.all().project_id.Здесь мы видим, что я пытаюсь получить доступ к атрибуту project_id из набора запросов.Правильный вариант использования будет MyModel.objects.all()[0].project_id.Однако это предполагает, что набор запросов не является пустым.

Практически, большинство представлений DjangoRestFramework наследуются от rest_framework.views.APIView, который подклассов класса представления django.Я бы посоветовал проверить, что query_set в этом классе используется правильно.

Не стесняйтесь поделиться своей реализацией здесь для дальнейшего комментария.

[EDIT] - После views.pyдобавлен код.

Вы пытаетесь сериализовать весь набор запросов с созданием экземпляра сериализатора data = AWDSerializer(deployments).data, это вызывает ошибку атрибута.

Я бы порекомендовал generics.ListAPIView класс и использование атрибутов класса query_set и serializer_class.Это просто реализовать.Затем вы можете вызвать метод get по умолчанию для APIViews.Вот пример для вашего 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')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...