Как заставить мой сериализатор возвращать данные из зависимого поля в моей модели? - PullRequest
0 голосов
/ 24 апреля 2020

Я использую Django 2 и Python 3.7. У меня есть эти модели настроены. Один (Coop) зависит от другого (CoopType), используя Many-To-Many ...

class CoopTypeManager(models.Manager):

    def get_by_natural_key(self, name):
        return self.get_or_create(name=name)[0]


class CoopType(models.Model):
    name = models.CharField(max_length=200, null=False, unique=True)

    objects = CoopTypeManager()


class CoopManager(models.Manager):
    # Look up by coop type
    def get_by_type(self, type):
        qset = Coop.objects.filter(type__name=type,
                                   enabled=True)
        return qset

    # Look up coops by a partial name (case insensitive)
    def find_by_name(self, partial_name):
        queryset = Coop.objects.filter(name__icontains=partial_name, enabled=True)
        print(queryset.query)
        return queryset

    # Meant to look up coops case-insensitively by part of a type
    def contains_type(self, types_arr):
        filter = Q(
            *[('type__name__icontains', type) for type in types_arr],
            _connector=Q.OR
        )
        queryset = Coop.objects.filter(filter,
                                       enabled=True)
        return queryset


class Coop(models.Model):
    objects = CoopManager()
    name = models.CharField(max_length=250, null=False)
    types = models.ManyToManyField(CoopType)
    address = AddressField(on_delete=models.CASCADE)
    enabled = models.BooleanField(default=True, null=False)
    phone = PhoneNumberField(null=True)
    email = models.EmailField(null=True)
    web_site = models.TextField()

У меня установлены следующие сериализаторы, предназначенные для возврата данных в JSON form ...

class CoopTypeField(serializers.PrimaryKeyRelatedField):

    queryset = CoopType.objects

    def to_internal_value(self, data):
        if type(data) == dict:
            cooptype, created = CoopType.objects.get_or_create(**data)
            # Replace the dict with the ID of the newly obtained object
            data = cooptype.pk
        return super().to_internal_value(data)

...
class CoopTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = CoopType
        fields = ['id', 'name']

    def create(self, validated_data):
        """
        Create and return a new `CoopType` instance, given the validated data.
        """
        return CoopType.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `CoopType` instance, given the validated data.
        """
        instance.name = validated_data.get('name', instance.name)
        instance.save()
        return instance


class CoopSerializer(serializers.ModelSerializer):
    types = CoopTypeSerializer(many=True)
    address = AddressTypeField()

    class Meta:
        model = Coop
        fields = ['id', 'name', 'types', 'address', 'phone', 'enabled', 'email', 'web_site']
        extra_kwargs = {
            'phone': {
                'required': False,
                'allow_blank': True
            }
        }

    def to_representation(self, instance):
        rep = super().to_representation(instance)
        rep['types'] = CoopTypeSerializer(instance.types).data
        rep['address'] = AddressSerializer(instance.address).data
        return rep

    def create(self, validated_data):
        #"""
        #Create and return a new `Snippet` instance, given the validated data.

        coop_types = validated_data.pop('types', {})
        instance = super().create(validated_data)
        for item in coop_types:
            coop_type, _ = CoopType.objects.get_or_create(name=item['name'])  #**item)
            instance.types.add(coop_type)

        return instance

Однако зависимое поле «тип» всегда возвращается как «ноль», несмотря на то, что я вижу, что в базе данных есть действительные данные. Вот что происходит, когда я запускаю свой запрос curl

curl -v --header "Content-type: application/json" --request GET "http://127.0.0.1:8000/coops/?contains=resource"
[{"id":348,"name":"Garden Resources of Woodlawn (GRoW)","types":{"name":null}

Как мне отредактировать мой сериализатор так, чтобы он возвращал значения зависимого типа?

1 Ответ

1 голос
/ 24 апреля 2020

Попробуйте удалить rep['types'] = CoopTypeSerializer(instance.types).data из to_representation(...) метода,

def to_representation(self, instance):
    rep = super().to_representation(instance)
    <b><strike>rep['types'] = CoopTypeSerializer(instance.types).data</strike></b>
    rep['address'] = AddressSerializer(instance.address).data
    return rep

ИЛИ
используйте instance.types.all() вместо instance.types, потому что здесь instance.types - это метод Manager , который не возвращает QuerySet

def to_representation(self, instance):
    rep = super().to_representation(instance)
    rep['types'] = CoopTypeSerializer(<b>instance.types.all(), many=True</b>).data
    rep['address'] = AddressSerializer(instance.address).data
    return rep
...