#django #django-rest-framework #django-serializer #django-rest-viewsets
#django #django-rest-framework #django-сериализатор #django-rest-viewsets
Вопрос:
У меня есть Land
модель с тремя отношениями, одно из которых Letter
и модель:
class Letter(models.Model):
land = models.ForeignKey('Land', on_delete=models.DO_NOTHING)
image = models.ImageField(null=True, upload_to=letter_image_file_path)
text = models.TextField(null=True, blank=True)
def __str__(self):
return str(self.id)
и его сериализатор
class LettersSerializer(serializers.ModelSerializer):
class Meta:
model = Letter
fields = ('id', 'text', 'image', 'land',)
read_only_fields = ('id',)
и Land
сериализатор:
class LandSerializer(serializers.ModelSerializer):
utm_points = UTMPointsSerializer(many=True, read_only=True)
letters = LettersSerializer(many=True, read_only=True)
их представления :
class BasicViewSet(viewsets.ModelViewSet):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
class LandViewSet(BasicViewSet):
serializer_class = LandSerializer
queryset = Land.objects.all()
class UTMPointViewSet(BasicViewSet):
serializer_class = UTMPointsSerializer
queryset = UTMPoint.objects.all()
class LettersViewSet(BasicViewSet):
serializer_class = LettersSerializer
queryset = Letter.objects.all()
но когда я отправляю GET
запрос, он не показывает letters
поле: вот ответ:
{
"id": 1,
"utm_points": []
}
хотя utm_points
и letters
точно такие же, но они имеют разные результаты.
Land
модель имеет user
отношение, которое я удалил для простоты.
После некоторых проб и ошибок я понятия не имею, почему в результате нет letters
поля.
Ответ №1:
Вам нужно объяснить LetterSerializer
, какой сериализатор использовать для сериализации Land
. Вы не можете использовать LandSerializer
, поскольку это создало бы циклическую зависимость, но что более важно: возможно, бесконечная рекурсия в ответе, поскольку a Letter
имеет a land
и land then serializes its related
буквы и т.д.
Таким образом, мы создаем простой сериализатор для Land
:
class SimpleLandSerializer(serializers.ModelSerializer):
utm_points = UTMPointsSerializer(many=True, read_only=True)
class Meta:
model = Land
fields = ['utm_points']
а затем используйте это в сериализаторе для land
:
class LettersSerializer(serializers.ModelSerializer):
land = SimpleLandSerializer()
class Meta:
model = Letter
fields = ('id', 'text', 'image', 'land',)
read_only_fields = ('id',)
РЕДАКТИРОВАТЬ: вы также можете сериализовать с помощью первичного ключа, в этом случае вы можете сериализовать с помощью PrimaryKeyRelatedField
[drf-doc]:
class LettersSerializer(serializers.ModelSerializer):
land = PrimaryKeyRelatedField()
class Meta:
model = Letter
fields = ('id', 'text', 'image', 'land',)
read_only_fields = ('id',)
РЕДАКТИРОВАТЬ 2: Другая проблема заключается в том, что ваше letters
отношение не существует, если вы хотите переименовать отношение из letter_set
в letters
, вы используете:
class Letter(models.Model):
land = models.ForeignKey(
'Land',
related_name='letters',
on_delete=models.DO_NOTHING
)
Комментарии:
1. На самом деле мне нужно показать буквы в ответе land, но вы предлагаете
LettersSerializer
показать сериализатор land, с другой стороны, Letter и UTMPoints точно такие же. так почему же просто буква не отображается?2. @moslem: потому что это приведет к циклу сериализации, в котором, если вы сериализуете a
Letter
, вы сериализуете егоland
, чтоland
затем сериализует новыеLetter
s, которые снова сериализуют land, так что JSON будет выглядеть{'land': {'letters': [{'land': ...}]}}
и, таким образом, приведет к ответу бесконечной длины.3. Нет
LettersSerializer
, просто сериализуетсяid
Land
, вы можете видеть это в определении сериализатора иutm
имеет точно такую же реализацию, но без каких-либо проблем4. У вас
LettersSerializer
есть asfieldds = ('id', 'text', 'image', 'land')
…5. Да, но он просто сериализует идентификатор, который является результатом
{ "id": 2, "text": "test", "image": null, "land": 1 },